summaryrefslogtreecommitdiff
path: root/ufs/alloc.c
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2013-09-17 19:20:42 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2013-09-17 19:20:42 +0200
commit84cf9c0f312637b670cc87224ff7e7c4da659e36 (patch)
tree5e7f0f1f6c7579d1275bb5cf1856ce52767ac8b3 /ufs/alloc.c
parent3e6aab0243da094f1ca05b80eb3e5a9adb8ea519 (diff)
Remove UFS support
It has been unused/untested/unmaintained for a decade now, and its 4-clause BSD licence poses problem. * configure.ac (default_static): Remove ufs. * Makefile (prog-subdirs): Remove ufs, ufs-fsck and ufs-utils. * NEWS, TODO: doc/hurd.texi, doc/navigating: Remove UFS notes. * ufs: Remove directory * ufs-fsck: Remove directory * ufs-utils: Remove directory * bsdfsck: Remove directory
Diffstat (limited to 'ufs/alloc.c')
-rw-r--r--ufs/alloc.c1703
1 files changed, 0 insertions, 1703 deletions
diff --git a/ufs/alloc.c b/ufs/alloc.c
deleted file mode 100644
index 9056a8b7..00000000
--- a/ufs/alloc.c
+++ /dev/null
@@ -1,1703 +0,0 @@
-/* Disk allocation routines
- Copyright (C) 1993,94,95,96,98,2002 Free Software Foundation, Inc.
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Modified from UCB by Michael I. Bushnell. */
-/*
- * Copyright (c) 1982, 1986, 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)ffs_alloc.c 8.8 (Berkeley) 2/21/94
- */
-
-#include "ufs.h"
-#include <stdio.h>
-#include <string.h>
-
-
-/* These don't work *at all* here; don't even try setting them. */
-#undef DIAGNOSTIC
-#undef QUOTA
-
-extern u_long nextgennumber;
-
-pthread_spinlock_t alloclock = PTHREAD_SPINLOCK_INITIALIZER;
-
-/* Forward declarations */
-static u_long ffs_hashalloc (struct node *, int, long, int,
- u_long (*)(struct node *, int, daddr_t, int));
-static u_long ffs_alloccg (struct node *, int, daddr_t, int);
-static daddr_t ffs_fragextend (struct node *, int, long, int, int);
-static ino_t ffs_dirpref (struct fs *);
-static u_long ffs_nodealloccg (struct node *, int, daddr_t, int);
-static daddr_t ffs_alloccgblk (struct fs *, struct cg *, daddr_t);
-static daddr_t ffs_mapsearch (struct fs *, struct cg *, daddr_t, int);
-static void ffs_clusteracct (struct fs *, struct cg *, daddr_t, int);
-
-/* Sync all allocation information and nod eNP if diskfs_synchronous. */
-inline void
-alloc_sync (struct node *np)
-{
- if (diskfs_synchronous)
- {
- if (np)
- diskfs_node_update (np, 1);
- copy_sblock ();
- diskfs_set_hypermetadata (1, 0);
- sync_disk (1);
- }
-}
-
-/* Byteswap everything in CGP. */
-void
-swab_cg (struct cg *cg)
-{
- int i, j;
-
- if (swab_long (cg->cg_magic) == CG_MAGIC
- || cg->cg_magic == CG_MAGIC)
- {
- cg->cg_magic = swab_long (cg->cg_magic);
- cg->cg_time = swab_long (cg->cg_time);
- cg->cg_cgx = swab_long (cg->cg_cgx);
- cg->cg_ncyl = swab_short (cg->cg_ncyl);
- cg->cg_niblk = swab_short (cg->cg_niblk);
- cg->cg_cs.cs_ndir = swab_long (cg->cg_cs.cs_ndir);
- cg->cg_cs.cs_nbfree = swab_long (cg->cg_cs.cs_nbfree);
- cg->cg_cs.cs_nifree = swab_long (cg->cg_cs.cs_nifree);
- cg->cg_cs.cs_nffree = swab_long (cg->cg_cs.cs_nffree);
- cg->cg_rotor = swab_long (cg->cg_rotor);
- cg->cg_irotor = swab_long (cg->cg_irotor);
- for (i = 0; i < MAXFRAG; i++)
- cg->cg_frsum[i] = swab_long (cg->cg_frsum[i]);
- cg->cg_btotoff = swab_long (cg->cg_btotoff);
- cg->cg_boff = swab_long (cg->cg_boff);
- cg->cg_iusedoff = swab_long (cg->cg_iusedoff);
- cg->cg_freeoff = swab_long (cg->cg_freeoff);
- cg->cg_nextfreeoff = swab_long (cg->cg_nextfreeoff);
- cg->cg_clustersumoff = swab_long (cg->cg_clustersumoff);
- cg->cg_clusteroff = swab_long (cg->cg_clusteroff);
- cg->cg_nclusterblks = swab_long (cg->cg_nclusterblks);
-
- /* blktot map */
- for (i = 0; i < cg->cg_ncyl; i++)
- cg_blktot(cg)[i] = swab_long (cg_blktot(cg)[i]);
-
- /* blks map */
- for (i = 0; i < cg->cg_ncyl; i++)
- for (j = 0; j < sblock->fs_nrpos; j++)
- cg_blks(sblock, cg, i)[j] = swab_short (cg_blks (sblock, cg, i)[j]);
-
- for (i = 0; i < sblock->fs_contigsumsize; i++)
- cg_clustersum(cg)[i] = swab_long (cg_clustersum(cg)[i]);
-
- /* inosused, blksfree, and cg_clustersfree are char arrays */
- }
- else
- {
- /* Old format cylinder group... */
- struct ocg *ocg = (struct ocg *) cg;
-
- if (swab_long (ocg->cg_magic) != CG_MAGIC
- && ocg->cg_magic != CG_MAGIC)
- return;
-
- ocg->cg_time = swab_long (ocg->cg_time);
- ocg->cg_cgx = swab_long (ocg->cg_cgx);
- ocg->cg_ncyl = swab_short (ocg->cg_ncyl);
- ocg->cg_niblk = swab_short (ocg->cg_niblk);
- ocg->cg_ndblk = swab_long (ocg->cg_ndblk);
- ocg->cg_cs.cs_ndir = swab_long (ocg->cg_cs.cs_ndir);
- ocg->cg_cs.cs_nbfree = swab_long (ocg->cg_cs.cs_nbfree);
- ocg->cg_cs.cs_nifree = swab_long (ocg->cg_cs.cs_nifree);
- ocg->cg_cs.cs_nffree = swab_long (ocg->cg_cs.cs_nffree);
- ocg->cg_rotor = swab_long (ocg->cg_rotor);
- ocg->cg_frotor = swab_long (ocg->cg_frotor);
- ocg->cg_irotor = swab_long (ocg->cg_irotor);
- for (i = 0; i < 8; i++)
- ocg->cg_frsum[i] = swab_long (ocg->cg_frsum[i]);
- for (i = 0; i < 32; i++)
- ocg->cg_btot[i] = swab_long (ocg->cg_btot[i]);
- for (i = 0; i < 32; i++)
- for (j = 0; j < 8; j++)
- ocg->cg_b[i][j] = swab_short (ocg->cg_b[i][j]);
- ocg->cg_magic = swab_long (ocg->cg_magic);
- }
-}
-
-
-/* Read cylinder group indexed CG. Set *CGPP to point at it.
- Return 1 if caller should call release_cgp when we're done with it;
- otherwise zero. */
-int
-read_cg (int cg, struct cg **cgpp)
-{
- struct cg *diskcg = cg_locate (cg);
-
- if (swab_disk)
- {
- *cgpp = malloc (sblock->fs_cgsize);
- bcopy (diskcg, *cgpp, sblock->fs_cgsize);
- swab_cg (*cgpp);
- return 1;
- }
- else
- {
- *cgpp = diskcg;
- return 0;
- }
-}
-
-/* Caller of read_cg is done with cg; write it back to disk (swapping it
- along the way) and free the memory allocated in read_cg. */
-void
-release_cg (struct cg *cgp)
-{
- int cgx = cgp->cg_cgx;
- swab_cg (cgp);
- bcopy (cgp, cg_locate (cgx), sblock->fs_cgsize);
- free (cgp);
-}
-
-
-/*
- * Allocate a block in the file system.
- *
- * The size of the requested block is given, which must be some
- * multiple of fs_fsize and <= fs_bsize.
- * A preference may be optionally specified. If a preference is given
- * the following hierarchy is used to allocate a block:
- * 1) allocate the requested block.
- * 2) allocate a rotationally optimal block in the same cylinder.
- * 3) allocate a block in the same cylinder group.
- * 4) quadradically rehash into other cylinder groups, until an
- * available block is located.
- * If no block preference is given the following hierarchy is used
- * to allocate a block:
- * 1) allocate a block in the cylinder group that contains the
- * inode for the file.
- * 2) quadradically rehash into other cylinder groups, until an
- * available block is located.
- */
-error_t
-ffs_alloc(register struct node *np,
- daddr_t lbn,
- daddr_t bpref,
- int size,
- daddr_t *bnp,
- struct protid *cred)
-{
- register struct fs *fs;
- daddr_t bno;
- int cg;
-
- *bnp = 0;
- fs = sblock;
-#ifdef DIAGNOSTIC
- if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) {
- printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
- ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt);
- panic("ffs_alloc: bad size");
- }
- assert (cred);
-#endif /* DIAGNOSTIC */
- pthread_spin_lock (&alloclock);
- if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
- goto nospace;
- if (cred && !idvec_contains (cred->user->uids, 0)
- && freespace(fs, fs->fs_minfree) <= 0)
- goto nospace;
-#ifdef QUOTA
- if (error = chkdq(ip, (long)btodb(size), cred, 0))
- return (error);
-#endif
- if (bpref >= fs->fs_size)
- bpref = 0;
- if (bpref == 0)
- cg = ino_to_cg(fs, np->dn->number);
- else
- cg = dtog(fs, bpref);
- bno = (daddr_t)ffs_hashalloc(np, cg, (long)bpref, size,
- (u_long (*)())ffs_alloccg);
- if (bno > 0) {
- pthread_spin_unlock (&alloclock);
- np->dn_stat.st_blocks += btodb(size);
- np->dn_set_ctime = 1;
- np->dn_set_mtime = 1;
- *bnp = bno;
- alloc_sync (np);
- return (0);
- }
-#ifdef QUOTA
- /*
- * Restore user's disk quota because allocation failed.
- */
- (void) chkdq(ip, (long)-btodb(size), cred, FORCE);
-#endif
-nospace:
- pthread_spin_unlock (&alloclock);
- printf ("file system full");
-/* ffs_fserr(fs, cred->cr_uid, "file system full"); */
-/* uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); */
- return (ENOSPC);
-}
-
-/*
- * Reallocate a fragment to a bigger size
- *
- * The number and size of the old block is given, and a preference
- * and new size is also specified. The allocator attempts to extend
- * the original block. Failing that, the regular block allocator is
- * invoked to get an appropriate block.
- */
-error_t
-ffs_realloccg(register struct node *np,
- daddr_t lbprev,
- volatile daddr_t bpref,
- int osize,
- int nsize,
- daddr_t *pbn,
- struct protid *cred)
-{
- register struct fs *fs;
- int cg, error;
- volatile int request;
- daddr_t bprev, bno;
-
- *pbn = 0;
- fs = sblock;
-#ifdef DIAGNOSTIC
- if ((u_int)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
- (u_int)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
- printf(
- "dev = 0x%x, bsize = %d, osize = %d, nsize = %d, fs = %s\n",
- ip->i_dev, fs->fs_bsize, osize, nsize, fs->fs_fsmnt);
- panic("ffs_realloccg: bad size");
- }
- if (cred == NOCRED)
- panic("ffs_realloccg: missing credential\n");
-#endif /* DIAGNOSTIC */
-
- pthread_spin_lock (&alloclock);
-
- if (!idvec_contains (cred->user->uids, 0)
- && freespace(fs, fs->fs_minfree) <= 0)
- goto nospace;
- error = diskfs_catch_exception ();
- if (error)
- return error;
- bprev = read_disk_entry ((dino (np->dn->number))->di_db[lbprev]);
- diskfs_end_catch_exception ();
- assert ("old block not allocated" && bprev);
-
-#if 0 /* Not needed in GNU Hurd ufs */
- /*
- * Allocate the extra space in the buffer.
- */
- if (error = bread(ITOV(ip), lbprev, osize, NOCRED, &bp)) {
- brelse(bp);
- return (error);
- }
-#ifdef QUOTA
- if (error = chkdq(ip, (long)btodb(nsize - osize), cred, 0)) {
- brelse(bp);
- return (error);
- }
-#endif
-#endif /* 0 */
-
- /*
- * Check for extension in the existing location.
- */
- cg = dtog(fs, bprev);
- bno = ffs_fragextend(np, cg, (long)bprev, osize, nsize);
- if (bno) {
- assert (bno == bprev);
- pthread_spin_unlock (&alloclock);
- np->dn_stat.st_blocks += btodb(nsize - osize);
- np->dn_set_ctime = 1;
- np->dn_set_mtime = 1;
- *pbn = bno;
-#if 0 /* Not done this way in GNU Hurd ufs. */
- allocbuf(bp, nsize);
- bp->b_flags |= B_DONE;
- bzero((char *)bp->b_data + osize, (u_int)nsize - osize);
- *bpp = bp;
-#endif
- alloc_sync (np);
- return (0);
- }
- /*
- * Allocate a new disk location.
- */
- if (bpref >= fs->fs_size)
- bpref = 0;
- switch ((int)fs->fs_optim) {
- case FS_OPTSPACE:
- /*
- * Allocate an exact sized fragment. Although this makes
- * best use of space, we will waste time relocating it if
- * the file continues to grow. If the fragmentation is
- * less than half of the minimum free reserve, we choose
- * to begin optimizing for time.
- */
- request = nsize;
- if (fs->fs_minfree < 5 ||
- fs->fs_cstotal.cs_nffree >
- fs->fs_dsize * fs->fs_minfree / (2 * 100))
- break;
- printf ("%s: optimization changed from SPACE to TIME\n",
- fs->fs_fsmnt);
- fs->fs_optim = FS_OPTTIME;
- break;
- case FS_OPTTIME:
- /*
- * At this point we have discovered a file that is trying to
- * grow a small fragment to a larger fragment. To save time,
- * we allocate a full sized block, then free the unused portion.
- * If the file continues to grow, the `ffs_fragextend' call
- * above will be able to grow it in place without further
- * copying. If aberrant programs cause disk fragmentation to
- * grow within 2% of the free reserve, we choose to begin
- * optimizing for space.
- */
- request = fs->fs_bsize;
- if (fs->fs_cstotal.cs_nffree <
- fs->fs_dsize * (fs->fs_minfree - 2) / 100)
- break;
- printf ("%s: optimization changed from TIME to SPACE\n",
- fs->fs_fsmnt);
- fs->fs_optim = FS_OPTSPACE;
- break;
- default:
- assert (0);
- /* NOTREACHED */
- }
- bno = (daddr_t)ffs_hashalloc(np, cg, (long)bpref, request,
- (u_long (*)())ffs_alloccg);
- if (bno > 0) {
-#if 0 /* Not necessary in GNU Hurd ufs */
- bp->b_blkno = fsbtodb(fs, bno);
- (void) vnode_pager_uncache(ITOV(ip));
-#endif
-/* Commented out here for Hurd; we don't want to free this until we've
- saved the old contents. Callers are responsible for freeing the
- block when they are done with it. */
-/* ffs_blkfree(np, bprev, (long)osize); */
- if (nsize < request)
- ffs_blkfree(np, bno + numfrags(fs, nsize),
- (long)(request - nsize));
- pthread_spin_unlock (&alloclock);
- np->dn_stat.st_blocks += btodb(nsize - osize);
- np->dn_set_mtime = 1;
- np->dn_set_ctime = 1;
- *pbn = bno;
-#if 0 /* Not done this way in GNU Hurd ufs */
- allocbuf(bp, nsize);
- bp->b_flags |= B_DONE;
- bzero((char *)bp->b_data + osize, (u_int)nsize - osize);
- *bpp = bp;
-#endif /* 0 */
- alloc_sync (np);
- return (0);
- }
-#ifdef QUOTA
- /*
- * Restore user's disk quota because allocation failed.
- */
- (void) chkdq(ip, (long)-btodb(nsize - osize), cred, FORCE);
-#endif
-#if 0 /* Not necesarry in GNU Hurd ufs */
- brelse(bp);
-#endif
-nospace:
- /*
- * no space available
- */
- pthread_spin_unlock (&alloclock);
- printf ("file system full");
-/* ffs_fserr(fs, cred->cr_uid, "file system full"); */
-/* uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); */
- return (ENOSPC);
-}
-
-#if 0 /* Not used (yet?) in GNU Hurd ufs */
-/*
- * Reallocate a sequence of blocks into a contiguous sequence of blocks.
- *
- * The vnode and an array of buffer pointers for a range of sequential
- * logical blocks to be made contiguous is given. The allocator attempts
- * to find a range of sequential blocks starting as close as possible to
- * an fs_rotdelay offset from the end of the allocation for the logical
- * block immediately preceding the current range. If successful, the
- * physical block numbers in the buffer pointers and in the inode are
- * changed to reflect the new allocation. If unsuccessful, the allocation
- * is left unchanged. The success in doing the reallocation is returned.
- * Note that the error return is not reflected back to the user. Rather
- * the previous block allocation will be used.
- */
-#include <sys/sysctl.h>
-int doasyncfree = 1;
-struct ctldebug debug14 = { "doasyncfree", &doasyncfree };
-int
-ffs_reallocblks(ap)
- struct vop_reallocblks_args /* {
- struct vnode *a_vp;
- struct cluster_save *a_buflist;
- } */ *ap;
-{
- struct fs *fs;
- struct inode *ip;
- struct vnode *vp;
- struct buf *sbp, *ebp;
- daddr_t *bap, *sbap, *ebap;
- struct cluster_save *buflist;
- daddr_t start_lbn, end_lbn, soff, eoff, newblk, blkno;
- struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
- int i, len, start_lvl, end_lvl, pref, ssize;
-
- vp = ap->a_vp;
- ip = VTOI(vp);
- fs = ip->i_fs;
- if (fs->fs_contigsumsize <= 0)
- return (ENOSPC);
- buflist = ap->a_buflist;
- len = buflist->bs_nchildren;
- start_lbn = buflist->bs_children[0]->b_lblkno;
- end_lbn = start_lbn + len - 1;
-#ifdef DIAGNOSTIC
- for (i = 1; i < len; i++)
- if (buflist->bs_children[i]->b_lblkno != start_lbn + i)
- panic("ffs_reallocblks: non-cluster");
-#endif
- /*
- * If the latest allocation is in a new cylinder group, assume that
- * the filesystem has decided to move and do not force it back to
- * the previous cylinder group.
- */
- if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) !=
- dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno)))
- return (ENOSPC);
- if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) ||
- ufs_getlbns(vp, end_lbn, end_ap, &end_lvl))
- return (ENOSPC);
- /*
- * Get the starting offset and block map for the first block.
- */
- if (start_lvl == 0) {
- sbap = &ip->i_db[0];
- soff = start_lbn;
- } else {
- idp = &start_ap[start_lvl - 1];
- if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &sbp)) {
- brelse(sbp);
- return (ENOSPC);
- }
- sbap = (daddr_t *)sbp->b_data;
- soff = idp->in_off;
- }
- /*
- * Find the preferred location for the cluster.
- */
- pref = ffs_blkpref(ip, start_lbn, soff, sbap);
- /*
- * If the block range spans two block maps, get the second map.
- */
- if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
- ssize = len;
- } else {
-#ifdef DIAGNOSTIC
- if (start_ap[start_lvl-1].in_lbn == idp->in_lbn)
- panic("ffs_reallocblk: start == end");
-#endif
- ssize = len - (idp->in_off + 1);
- if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp))
- goto fail;
- ebap = (daddr_t *)ebp->b_data;
- }
- /*
- * Search the block map looking for an allocation of the desired size.
- */
- if ((newblk = (daddr_t)ffs_hashalloc(ip, dtog(fs, pref), (long)pref,
- len, (u_long (*)())ffs_clusteralloc)) == 0)
- goto fail;
- /*
- * We have found a new contiguous block.
- *
- * First we have to replace the old block pointers with the new
- * block pointers in the inode and indirect blocks associated
- * with the file.
- */
- blkno = newblk;
- for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) {
- if (i == ssize)
- bap = ebap;
-#ifdef DIAGNOSTIC
- if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
- panic("ffs_reallocblks: alloc mismatch");
-#endif
- *bap++ = blkno;
- }
- /*
- * Next we must write out the modified inode and indirect blocks.
- * For strict correctness, the writes should be synchronous since
- * the old block values may have been written to disk. In practise
- * they are almost never written, but if we are concerned about
- * strict correctness, the `doasyncfree' flag should be set to zero.
- *
- * The test on `doasyncfree' should be changed to test a flag
- * that shows whether the associated buffers and inodes have
- * been written. The flag should be set when the cluster is
- * started and cleared whenever the buffer or inode is flushed.
- * We can then check below to see if it is set, and do the
- * synchronous write only when it has been cleared.
- */
- if (sbap != &ip->i_db[0]) {
- if (doasyncfree)
- bdwrite(sbp);
- else
- bwrite(sbp);
- } else {
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
- if (!doasyncfree)
- VOP_UPDATE(vp, &time, &time, MNT_WAIT);
- }
- if (ssize < len)
- if (doasyncfree)
- bdwrite(ebp);
- else
- bwrite(ebp);
- /*
- * Last, free the old blocks and assign the new blocks to the buffers.
- */
- for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) {
- ffs_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
- fs->fs_bsize);
- buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
- }
- return (0);
-
-fail:
- if (ssize < len)
- brelse(ebp);
- if (sbap != &ip->i_db[0])
- brelse(sbp);
- return (ENOSPC);
-}
-#endif /* 0 */
-
-/*
- * Allocate an inode in the file system.
- *
- * If allocating a directory, use ffs_dirpref to select the inode.
- * If allocating in a directory, the following hierarchy is followed:
- * 1) allocate the preferred inode.
- * 2) allocate an inode in the same cylinder group.
- * 3) quadradically rehash into other cylinder groups, until an
- * available inode is located.
- * If no inode preference is given the following hierarchy is used
- * to allocate an inode:
- * 1) allocate an inode in cylinder group 0.
- * 2) quadradically rehash into other cylinder groups, until an
- * available inode is located.
- */
-/* This is now the diskfs_alloc_node callback from the diskfs library
- (described in <hurd/diskfs.h>). It used to be ffs_valloc in BSD. */
-error_t
-diskfs_alloc_node (struct node *dir,
- mode_t mode,
- struct node **npp)
-{
- register struct fs *fs;
- struct node *np;
- ino_t ino, ipref;
- int cg, error;
- int sex;
-
- fs = sblock;
-
-
- pthread_spin_lock (&alloclock);
-
- if (fs->fs_cstotal.cs_nifree == 0)
- {
- pthread_spin_unlock (&alloclock);
- goto noinodes;
- }
-
- if (S_ISDIR (mode))
- ipref = ffs_dirpref(fs);
- else
- ipref = dir->dn->number;
-
- if (ipref >= fs->fs_ncg * fs->fs_ipg)
- ipref = 0;
- cg = ino_to_cg(fs, ipref);
- ino = (ino_t)ffs_hashalloc(dir, cg, (long)ipref,
- mode, ffs_nodealloccg);
- pthread_spin_unlock (&alloclock);
- if (ino == 0)
- goto noinodes;
- error = diskfs_cached_lookup (ino, &np);
- assert ("duplicate allocation" && !np->dn_stat.st_mode);
- assert (! (np->dn_stat.st_mode & S_IPTRANS));
- if (np->dn_stat.st_blocks) {
- printf("free inode %Ld had %Ld blocks\n",
- ino, np->dn_stat.st_blocks);
- np->dn_stat.st_blocks = 0;
- np->dn_set_ctime = 1;
- }
- np->dn_stat.st_flags = 0;
- /*
- * Set up a new generation number for this inode.
- */
- pthread_spin_lock (&gennumberlock);
- sex = diskfs_mtime->seconds;
- if (++nextgennumber < (u_long)sex)
- nextgennumber = sex;
- np->dn_stat.st_gen = nextgennumber;
- pthread_spin_unlock (&gennumberlock);
-
- *npp = np;
- alloc_sync (np);
- return (0);
-noinodes:
- printf ("out of inodes");
-/* ffs_fserr(fs, ap->a_cred->cr_uid, "out of inodes"); */
-/* uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);*/
- return (ENOSPC);
-}
-
-/*
- * Find a cylinder to place a directory.
- *
- * The policy implemented by this algorithm is to select from
- * among those cylinder groups with above the average number of
- * free inodes, the one with the smallest number of directories.
- */
-static ino_t
-ffs_dirpref(register struct fs *fs)
-{
- int cg, minndir, mincg, avgifree;
-
- avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg;
- minndir = fs->fs_ipg;
- mincg = 0;
- for (cg = 0; cg < fs->fs_ncg; cg++)
- if (csum[cg].cs_ndir < minndir &&
- csum[cg].cs_nifree >= avgifree) {
- mincg = cg;
- minndir = csum[cg].cs_ndir;
- }
- return ((ino_t)(fs->fs_ipg * mincg));
-}
-
-/*
- * Select the desired position for the next block in a file. The file is
- * logically divided into sections. The first section is composed of the
- * direct blocks. Each additional section contains fs_maxbpg blocks.
- *
- * If no blocks have been allocated in the first section, the policy is to
- * request a block in the same cylinder group as the inode that describes
- * the file. If no blocks have been allocated in any other section, the
- * policy is to place the section in a cylinder group with a greater than
- * average number of free blocks. An appropriate cylinder group is found
- * by using a rotor that sweeps the cylinder groups. When a new group of
- * blocks is needed, the sweep begins in the cylinder group following the
- * cylinder group from which the previous allocation was made. The sweep
- * continues until a cylinder group with greater than the average number
- * of free blocks is found. If the allocation is for the first block in an
- * indirect block, the information on the previous allocation is unavailable;
- * here a best guess is made based upon the logical block number being
- * allocated.
- *
- * If a section is already partially allocated, the policy is to
- * contiguously allocate fs_maxcontig blocks. The end of one of these
- * contiguous blocks and the beginning of the next is physically separated
- * so that the disk head will be in transit between them for at least
- * fs_rotdelay milliseconds. This is to allow time for the processor to
- * schedule another I/O transfer.
- */
-daddr_t
-ffs_blkpref(struct node *np,
- daddr_t lbn,
- int indx,
- daddr_t *bap)
-{
- register struct fs *fs;
- register int cg;
- int avgbfree, startcg;
- daddr_t nextblk;
-
- fs = sblock;
- pthread_spin_lock (&alloclock);
- if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
- if (lbn < NDADDR) {
- cg = ino_to_cg(fs, np->dn->number);
- pthread_spin_unlock (&alloclock);
- return (fs->fs_fpg * cg + fs->fs_frag);
- }
- /*
- * Find a cylinder with greater than average number of
- * unused data blocks.
- */
- if (indx == 0 || bap[indx - 1] == 0)
- startcg =
- (ino_to_cg(fs, np->dn->number)
- + lbn / fs->fs_maxbpg);
- else
- startcg = dtog(fs,
- read_disk_entry (bap[indx - 1])) + 1;
- startcg %= fs->fs_ncg;
- avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
- for (cg = startcg; cg < fs->fs_ncg; cg++)
- if (csum[cg].cs_nbfree >= avgbfree) {
- fs->fs_cgrotor = cg;
- pthread_spin_unlock (&alloclock);
- return (fs->fs_fpg * cg + fs->fs_frag);
- }
- for (cg = 0; cg <= startcg; cg++)
- if (csum[cg].cs_nbfree >= avgbfree) {
- fs->fs_cgrotor = cg;
- pthread_spin_unlock (&alloclock);
- return (fs->fs_fpg * cg + fs->fs_frag);
- }
- pthread_spin_unlock (&alloclock);
- return 0;
- }
- pthread_spin_unlock (&alloclock);
- /*
- * One or more previous blocks have been laid out. If less
- * than fs_maxcontig previous blocks are contiguous, the
- * next block is requested contiguously, otherwise it is
- * requested rotationally delayed by fs_rotdelay milliseconds.
- */
- nextblk = read_disk_entry (bap[indx - 1]) + fs->fs_frag;
- if (indx < fs->fs_maxcontig
- || (read_disk_entry (bap[indx - fs->fs_maxcontig]) +
- blkstofrags(fs, fs->fs_maxcontig) != nextblk))
- {
- return (nextblk);
- }
- if (fs->fs_rotdelay != 0)
- /*
- * Here we convert ms of delay to frags as:
- * (frags) = (ms) * (rev/sec) * (sect/rev) /
- * ((sect/frag) * (ms/sec))
- * then round up to the next block.
- */
- nextblk += roundup(fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect /
- (NSPF(fs) * 1000), fs->fs_frag);
- return (nextblk);
-}
-
-/*
- * Implement the cylinder overflow algorithm.
- *
- * The policy implemented by this algorithm is:
- * 1) allocate the block in its requested cylinder group.
- * 2) quadradically rehash on the cylinder group number.
- * 3) brute force search for a free block.
- */
-/*VARARGS5*/
-static u_long
-ffs_hashalloc(struct node *np,
- int cg,
- long pref,
- int size, /* size for data blocks, mode for inodes */
- u_long (*allocator)())
-{
- register struct fs *fs;
- long result;
- int i, icg = cg;
-
- fs = sblock;
- /*
- * 1: preferred cylinder group
- */
- result = (*allocator)(np, cg, pref, size);
- if (result)
- return (result);
- /*
- * 2: quadratic rehash
- */
- for (i = 1; i < fs->fs_ncg; i *= 2) {
- cg += i;
- if (cg >= fs->fs_ncg)
- cg -= fs->fs_ncg;
- result = (*allocator)(np, cg, 0, size);
- if (result)
- return (result);
- }
- /*
- * 3: brute force search
- * Note that we start at i == 2, since 0 was checked initially,
- * and 1 is always checked in the quadratic rehash.
- */
- cg = (icg + 2) % fs->fs_ncg;
- for (i = 2; i < fs->fs_ncg; i++) {
- result = (*allocator)(np, cg, 0, size);
- if (result)
- return (result);
- cg++;
- if (cg == fs->fs_ncg)
- cg = 0;
- }
- return 0;
-}
-
-/*
- * Determine whether a fragment can be extended.
- *
- * Check to see if the necessary fragments are available, and
- * if they are, allocate them.
- */
-static daddr_t
-ffs_fragextend(struct node *np,
- int cg,
- long bprev,
- int osize,
- int nsize)
-{
- register struct fs *fs;
- struct cg *cgp;
- long bno;
- int frags, bbase;
- int i;
- int releasecg;
-
- fs = sblock;
- if (csum[cg].cs_nffree < numfrags(fs, nsize - osize))
- return 0;
- frags = numfrags(fs, nsize);
- bbase = fragnum(fs, bprev);
- if (bbase > fragnum(fs, (bprev + frags - 1))) {
- /* cannot extend across a block boundary */
- return 0;
- }
-#if 0 /* Wrong for GNU Hurd ufs */
- error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
- (int)fs->fs_cgsize, NOCRED, &bp);
- if (error) {
- brelse(bp);
- return (NULL);
- }
- cgp = (struct cg *)bp->b_data;
-#else
- releasecg = read_cg (cg, &cgp);
-#endif
- if (!cg_chkmagic(cgp)) {
-/* brelse(bp); */
- if (releasecg)
- release_cg (cgp);
- return 0;
- }
- cgp->cg_time = diskfs_mtime->seconds;
- bno = dtogd(fs, bprev);
- for (i = numfrags(fs, osize); i < frags; i++)
- if (isclr(cg_blksfree(cgp), bno + i)) {
-/* brelse(bp); */
- if (releasecg)
- release_cg (cgp);
- return 0;
- }
- /*
- * the current fragment can be extended
- * deduct the count on fragment being extended into
- * increase the count on the remaining fragment (if any)
- * allocate the extended piece
- */
- for (i = frags; i < fs->fs_frag - bbase; i++)
- if (isclr(cg_blksfree(cgp), bno + i))
- break;
- cgp->cg_frsum[i - numfrags(fs, osize)]--;
- if (i != frags)
- cgp->cg_frsum[i - frags]++;
- for (i = numfrags(fs, osize); i < frags; i++) {
- clrbit(cg_blksfree(cgp), bno + i);
- cgp->cg_cs.cs_nffree--;
- fs->fs_cstotal.cs_nffree--;
- csum[cg].cs_nffree--;
- }
- if (releasecg)
- release_cg (cgp);
- record_poke (cgp, sblock->fs_cgsize);
- csum_dirty = 1;
- sblock_dirty = 1;
- fs->fs_fmod = 1;
-/* bdwrite(bp); */
- return (bprev);
-}
-
-/*
- * Determine whether a block can be allocated.
- *
- * Check to see if a block of the appropriate size is available,
- * and if it is, allocate it.
- */
-static u_long
-ffs_alloccg(struct node *np,
- int cg,
- daddr_t bpref,
- int size)
-{
- register struct fs *fs;
- struct cg *cgp;
- register int i;
- int bno, frags, allocsiz;
- int releasecg;
-
- fs = sblock;
- if (csum[cg].cs_nbfree == 0 && size == fs->fs_bsize)
- return 0;
-#if 0 /* Not this way in GNU Hurd ufs */
- error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
- (int)fs->fs_cgsize, NOCRED, &bp);
- if (error) {
- brelse(bp);
- return (NULL);
- }
- cgp = (struct cg *)bp->b_data;
-#else
- releasecg = read_cg (cg, &cgp);
-#endif
- if (!cg_chkmagic(cgp) ||
- (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
-/* brelse(bp); */
- if (releasecg)
- release_cg (cgp);
- return 0;
- }
- cgp->cg_time = diskfs_mtime->seconds;
- if (size == fs->fs_bsize) {
- bno = ffs_alloccgblk(fs, cgp, bpref);
-/* bdwrite(bp); */
- if (releasecg)
- release_cg (cgp);
- return (bno);
- }
- /*
- * check to see if any fragments are already available
- * allocsiz is the size which will be allocated, hacking
- * it down to a smaller size if necessary
- */
- frags = numfrags(fs, size);
- for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++)
- if (cgp->cg_frsum[allocsiz] != 0)
- break;
- if (allocsiz == fs->fs_frag) {
- /*
- * no fragments were available, so a block will be
- * allocated, and hacked up
- */
- if (cgp->cg_cs.cs_nbfree == 0) {
-/* brelse(bp); */
- if (releasecg)
- release_cg (cgp);
- return 0;
- }
- bno = ffs_alloccgblk(fs, cgp, bpref);
- bpref = dtogd(fs, bno);
- for (i = frags; i < fs->fs_frag; i++)
- setbit(cg_blksfree(cgp), bpref + i);
- i = fs->fs_frag - frags;
- cgp->cg_cs.cs_nffree += i;
- fs->fs_cstotal.cs_nffree += i;
- csum[cg].cs_nffree += i;
- fs->fs_fmod = 1;
- cgp->cg_frsum[i]++;
-
- if (releasecg)
- release_cg (cgp);
- record_poke (cgp, sblock->fs_cgsize);
- csum_dirty = 1;
- sblock_dirty = 1;
-/* bdwrite(bp); */
- return (bno);
- }
- bno = ffs_mapsearch(fs, cgp, bpref, allocsiz);
- if (bno < 0) {
-/* brelse(bp); */
- if (releasecg)
- release_cg (cgp);
- return 0;
- }
- for (i = 0; i < frags; i++)
- clrbit(cg_blksfree(cgp), bno + i);
- cgp->cg_cs.cs_nffree -= frags;
- fs->fs_cstotal.cs_nffree -= frags;
- csum[cg].cs_nffree -= frags;
- fs->fs_fmod = 1;
- cgp->cg_frsum[allocsiz]--;
- if (frags != allocsiz)
- cgp->cg_frsum[allocsiz - frags]++;
- if (releasecg)
- release_cg (cgp);
- record_poke (cgp, sblock->fs_cgsize);
- csum_dirty = 1;
- sblock_dirty = 1;
-/* bdwrite(bp); */
- return (cg * fs->fs_fpg + bno);
-}
-
-/*
- * Allocate a block in a cylinder group.
- *
- * This algorithm implements the following policy:
- * 1) allocate the requested block.
- * 2) allocate a rotationally optimal block in the same cylinder.
- * 3) allocate the next available block on the block rotor for the
- * specified cylinder group.
- * Note that this routine only allocates fs_bsize blocks; these
- * blocks may be fragmented by the routine that allocates them.
- */
-static daddr_t
-ffs_alloccgblk(register struct fs *fs,
- register struct cg *cgp,
- daddr_t bpref)
-{
- daddr_t bno, blkno;
- int cylno, pos, delta;
- short *cylbp;
- register int i;
-
- if (bpref == 0 || dtog(fs, bpref) != cgp->cg_cgx) {
- bpref = cgp->cg_rotor;
- goto norot;
- }
- bpref = blknum(fs, bpref);
- bpref = dtogd(fs, bpref);
- /*
- * if the requested block is available, use it
- */
- if (ffs_isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bpref))) {
- bno = bpref;
- goto gotit;
- }
- /*
- * check for a block available on the same cylinder
- */
- cylno = cbtocylno(fs, bpref);
- if (cg_blktot(cgp)[cylno] == 0)
- goto norot;
- if (fs->fs_cpc == 0) {
- /*
- * Block layout information is not available.
- * Leaving bpref unchanged means we take the
- * next available free block following the one
- * we just allocated. Hopefully this will at
- * least hit a track cache on drives of unknown
- * geometry (e.g. SCSI).
- */
- goto norot;
- }
- /*
- * check the summary information to see if a block is
- * available in the requested cylinder starting at the
- * requested rotational position and proceeding around.
- */
- cylbp = cg_blks(fs, cgp, cylno);
- pos = cbtorpos(fs, bpref);
- for (i = pos; i < fs->fs_nrpos; i++)
- if (cylbp[i] > 0)
- break;
- if (i == fs->fs_nrpos)
- for (i = 0; i < pos; i++)
- if (cylbp[i] > 0)
- break;
- if (cylbp[i] > 0) {
- /*
- * found a rotational position, now find the actual
- * block. A panic if none is actually there.
- */
- pos = cylno % fs->fs_cpc;
- bno = (cylno - pos) * fs->fs_spc / NSPB(fs);
- assert (fs_postbl(fs, pos)[i] != -1);
- for (i = fs_postbl(fs, pos)[i];; ) {
- if (ffs_isblock(fs, cg_blksfree(cgp), bno + i)) {
- bno = blkstofrags(fs, (bno + i));
- goto gotit;
- }
- delta = fs_rotbl(fs)[i];
- if (delta <= 0 ||
- delta + i > fragstoblks(fs, fs->fs_fpg))
- break;
- i += delta;
- }
- printf("pos = %d, i = %d, fs = %s\n", pos, i, fs->fs_fsmnt);
- assert (0);
- }
-norot:
- /*
- * no blocks in the requested cylinder, so take next
- * available one in this cylinder group.
- */
- bno = ffs_mapsearch(fs, cgp, bpref, (int)fs->fs_frag);
- if (bno < 0)
- return 0;
- cgp->cg_rotor = bno;
-gotit:
- blkno = fragstoblks(fs, bno);
- ffs_clrblock(fs, cg_blksfree(cgp), (long)blkno);
- ffs_clusteracct(fs, cgp, blkno, -1);
- cgp->cg_cs.cs_nbfree--;
- fs->fs_cstotal.cs_nbfree--;
- csum[cgp->cg_cgx].cs_nbfree--;
- cylno = cbtocylno(fs, bno);
- cg_blks(fs, cgp, cylno)[cbtorpos(fs, bno)]--;
- cg_blktot(cgp)[cylno]--;
- fs->fs_fmod = 1;
- record_poke (cgp, sblock->fs_cgsize);
- csum_dirty = 1;
- sblock_dirty = 1;
- return (cgp->cg_cgx * fs->fs_fpg + bno);
-}
-
-#if 0 /* Not needed in GNU Hurd ufs (yet?) */
-/*
- * Determine whether a cluster can be allocated.
- *
- * We do not currently check for optimal rotational layout if there
- * are multiple choices in the same cylinder group. Instead we just
- * take the first one that we find following bpref.
- */
-static daddr_t
-ffs_clusteralloc(ip, cg, bpref, len)
- struct inode *ip;
- int cg;
- daddr_t bpref;
- int len;
-{
- register struct fs *fs;
- register struct cg *cgp;
- struct buf *bp;
- int i, run, bno, bit, map;
- u_char *mapp;
-
- fs = ip->i_fs;
- if (fs->fs_cs(fs, cg).cs_nbfree < len)
- return (NULL);
- if (bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
- NOCRED, &bp))
- goto fail;
- cgp = (struct cg *)bp->b_data;
- if (!cg_chkmagic(cgp))
- goto fail;
- /*
- * Check to see if a cluster of the needed size (or bigger) is
- * available in this cylinder group.
- */
- for (i = len; i <= fs->fs_contigsumsize; i++)
- if (cg_clustersum(cgp)[i] > 0)
- break;
- if (i > fs->fs_contigsumsize)
- goto fail;
- /*
- * Search the cluster map to find a big enough cluster.
- * We take the first one that we find, even if it is larger
- * than we need as we prefer to get one close to the previous
- * block allocation. We do not search before the current
- * preference point as we do not want to allocate a block
- * that is allocated before the previous one (as we will
- * then have to wait for another pass of the elevator
- * algorithm before it will be read). We prefer to fail and
- * be recalled to try an allocation in the next cylinder group.
- */
- if (dtog(fs, bpref) != cg)
- bpref = 0;
- else
- bpref = fragstoblks(fs, dtogd(fs, blknum(fs, bpref)));
- mapp = &cg_clustersfree(cgp)[bpref / NBBY];
- map = *mapp++;
- bit = 1 << (bpref % NBBY);
- for (run = 0, i = bpref; i < cgp->cg_nclusterblks; i++) {
- if ((map & bit) == 0) {
- run = 0;
- } else {
- run++;
- if (run == len)
- break;
- }
- if ((i & (NBBY - 1)) != (NBBY - 1)) {
- bit <<= 1;
- } else {
- map = *mapp++;
- bit = 1;
- }
- }
- if (i == cgp->cg_nclusterblks)
- goto fail;
- /*
- * Allocate the cluster that we have found.
- */
- bno = cg * fs->fs_fpg + blkstofrags(fs, i - run + 1);
- len = blkstofrags(fs, len);
- for (i = 0; i < len; i += fs->fs_frag)
- if (ffs_alloccgblk(fs, cgp, bno + i) != bno + i)
- panic("ffs_clusteralloc: lost block");
- brelse(bp);
- return (bno);
-
-fail:
- brelse(bp);
- return (0);
-}
-#endif
-
-/*
- * Determine whether an inode can be allocated.
- *
- * Check to see if an inode is available, and if it is,
- * allocate it using the following policy:
- * 1) allocate the requested inode.
- * 2) allocate the next available inode after the requested
- * inode in the specified cylinder group.
- */
-static u_long
-ffs_nodealloccg(struct node *np,
- int cg,
- daddr_t ipref,
- int mode)
-{
- register struct fs *fs;
- struct cg *cgp;
- int start, len, loc, map, i;
- int releasecg;
-
- fs = sblock;
- if (csum[cg].cs_nifree == 0)
- return 0;
-#if 0 /* Not this way in GNU Hurd ufs */
- error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
- (int)fs->fs_cgsize, NOCRED, &bp);
- if (error) {
- brelse(bp);
- return (NULL);
- }
- cgp = (struct cg *)bp->b_data;
-#else
- releasecg = read_cg (cg, &cgp);
-#endif
- if (!cg_chkmagic(cgp) || cgp->cg_cs.cs_nifree == 0) {
-/* brelse(bp); */
- if (releasecg)
- release_cg (cgp);
- return 0;
- }
- cgp->cg_time = diskfs_mtime->seconds;
- if (ipref) {
- ipref %= fs->fs_ipg;
- if (isclr(cg_inosused(cgp), ipref))
- goto gotit;
- }
- start = cgp->cg_irotor / NBBY;
- len = howmany(fs->fs_ipg - cgp->cg_irotor, NBBY);
- loc = skpc(0xff, len, &cg_inosused(cgp)[start]);
- if (loc == 0) {
- len = start + 1;
- start = 0;
- loc = skpc(0xff, len, &cg_inosused(cgp)[0]);
- assert (loc != 0);
- }
- i = start + len - loc;
- map = cg_inosused(cgp)[i];
- ipref = i * NBBY;
- for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) {
- if ((map & i) == 0) {
- cgp->cg_irotor = ipref;
- goto gotit;
- }
- }
- assert (0);
- /* NOTREACHED */
-gotit:
- setbit(cg_inosused(cgp), ipref);
- cgp->cg_cs.cs_nifree--;
- fs->fs_cstotal.cs_nifree--;
- csum[cg].cs_nifree--;
- fs->fs_fmod = 1;
- if ((mode & IFMT) == IFDIR) {
- cgp->cg_cs.cs_ndir++;
- fs->fs_cstotal.cs_ndir++;
- csum[cg].cs_ndir++;
- }
- if (releasecg)
- release_cg (cgp);
- record_poke (cgp, sblock->fs_cgsize);
- csum_dirty = 1;
- sblock_dirty = 1;
-/* bdwrite(bp); */
- return (cg * fs->fs_ipg + ipref);
-}
-
-/*
- * Free a block or fragment.
- *
- * The specified block or fragment is placed back in the
- * free map. If a fragment is deallocated, a possible
- * block reassembly is checked.
- */
-void
-ffs_blkfree(register struct node *np,
- daddr_t bno,
- long size)
-{
- register struct fs *fs;
- struct cg *cgp;
- daddr_t blkno;
- int i, cg, blk, frags, bbase;
- int releasecg;
-
- fs = sblock;
- assert ((u_int)size <= fs->fs_bsize && !fragoff (fs, size));
- cg = dtog(fs, bno);
- if ((u_int)bno >= fs->fs_size) {
- printf("bad block %ld, ino %Ld\n", bno, np->dn->number);
-/* ffs_fserr(fs, ip->i_uid, "bad block"); */
- return;
- }
-#if 0 /* Not this way in GNU Hurd ufs */
- error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
- (int)fs->fs_cgsize, NOCRED, &bp);
- if (error) {
- brelse(bp);
- return;
- }
- cgp = (struct cg *)bp->b_data;
-#else
- releasecg = read_cg (cg, &cgp);
-#endif
- if (!cg_chkmagic(cgp)) {
-/* brelse(bp); */
- if (releasecg)
- release_cg (cgp);
- return;
- }
- cgp->cg_time = diskfs_mtime->seconds;
- bno = dtogd(fs, bno);
- if (size == fs->fs_bsize) {
- blkno = fragstoblks(fs, bno);
- assert (!ffs_isblock(fs, cg_blksfree (cgp), blkno));
- ffs_setblock(fs, cg_blksfree(cgp), blkno);
- ffs_clusteracct(fs, cgp, blkno, 1);
- cgp->cg_cs.cs_nbfree++;
- fs->fs_cstotal.cs_nbfree++;
- csum[cg].cs_nbfree++;
- i = cbtocylno(fs, bno);
- cg_blks(fs, cgp, i)[cbtorpos(fs, bno)]++;
- cg_blktot(cgp)[i]++;
- } else {
- bbase = bno - fragnum(fs, bno);
- /*
- * decrement the counts associated with the old frags
- */
- blk = blkmap(fs, cg_blksfree(cgp), bbase);
- ffs_fragacct(fs, blk, cgp->cg_frsum, -1);
- /*
- * deallocate the fragment
- */
- frags = numfrags(fs, size);
- for (i = 0; i < frags; i++) {
- assert (!isset (cg_blksfree(cgp), bno + i));
- setbit(cg_blksfree(cgp), bno + i);
- }
- cgp->cg_cs.cs_nffree += i;
- fs->fs_cstotal.cs_nffree += i;
- csum[cg].cs_nffree += i;
- /*
- * add back in counts associated with the new frags
- */
- blk = blkmap(fs, cg_blksfree(cgp), bbase);
- ffs_fragacct(fs, blk, cgp->cg_frsum, 1);
- /*
- * if a complete block has been reassembled, account for it
- */
- blkno = fragstoblks(fs, bbase);
- if (ffs_isblock(fs, cg_blksfree(cgp), blkno)) {
- cgp->cg_cs.cs_nffree -= fs->fs_frag;
- fs->fs_cstotal.cs_nffree -= fs->fs_frag;
- csum[cg].cs_nffree -= fs->fs_frag;
- ffs_clusteracct(fs, cgp, blkno, 1);
- cgp->cg_cs.cs_nbfree++;
- fs->fs_cstotal.cs_nbfree++;
- csum[cg].cs_nbfree++;
- i = cbtocylno(fs, bbase);
- cg_blks(fs, cgp, i)[cbtorpos(fs, bbase)]++;
- cg_blktot(cgp)[i]++;
- }
- }
- if (releasecg)
- release_cg (cgp);
- record_poke (cgp, sblock->fs_cgsize);
- csum_dirty = 1;
- sblock_dirty = 1;
- fs->fs_fmod = 1;
- alloc_sync (np);
-/* bdwrite(bp); */
-}
-
-/*
- * Free an inode.
- *
- * The specified inode is placed back in the free map.
- */
-/* Implement diskfs call back diskfs_free_node (described in
- <hurd/diskfs.h>. This was called ffs_vfree in BSD. */
-void
-diskfs_free_node (struct node *np, mode_t mode)
-{
- register struct fs *fs;
- struct cg *cgp;
- ino_t ino = np->dn->number;
- int cg;
- int releasecg;
-
- fs = sblock;
- assert (ino < fs->fs_ipg * fs->fs_ncg);
- cg = ino_to_cg(fs, ino);
-#if 0 /* Not this way in GNU Hurd ufs */
- error = bread(pip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
- (int)fs->fs_cgsize, NOCRED, &bp);
- if (error) {
- brelse(bp);
- return (0);
- }
- cgp = (struct cg *)bp->b_data;
-#else
- releasecg = read_cg (cg, &cgp);
-#endif
- if (!cg_chkmagic(cgp)) {
-/* brelse(bp); */
- if (releasecg)
- release_cg (cgp);
- return;
- }
- cgp->cg_time = diskfs_mtime->seconds;
- ino %= fs->fs_ipg;
- if (isclr(cg_inosused(cgp), ino)) {
-/* printf("dev = 0x%x, ino = %Ld, fs = %s\n",
- pip->i_dev, ino, fs->fs_fsmnt); */
- assert (diskfs_readonly);
- }
- clrbit(cg_inosused(cgp), ino);
- if (ino < cgp->cg_irotor)
- cgp->cg_irotor = ino;
- cgp->cg_cs.cs_nifree++;
- fs->fs_cstotal.cs_nifree++;
- csum[cg].cs_nifree++;
- if ((mode & IFMT) == IFDIR) {
- cgp->cg_cs.cs_ndir--;
- fs->fs_cstotal.cs_ndir--;
- csum[cg].cs_ndir--;
- }
- if (releasecg)
- release_cg (cgp);
- record_poke (cgp, sblock->fs_cgsize);
- csum_dirty = 1;
- sblock_dirty = 1;
- fs->fs_fmod = 1;
- alloc_sync (np);
-/* bdwrite(bp); */
-}
-
-/*
- * Find a block of the specified size in the specified cylinder group.
- *
- * It is a panic if a request is made to find a block if none are
- * available.
- */
-static daddr_t
-ffs_mapsearch(register struct fs *fs,
- register struct cg *cgp,
- daddr_t bpref,
- int allocsiz)
-{
- daddr_t bno;
- int start, len, loc, i;
- int blk, field, subfield, pos;
-
- /*
- * find the fragment by searching through the free block
- * map for an appropriate bit pattern
- */
- if (bpref)
- start = dtogd(fs, bpref) / NBBY;
- else
- start = cgp->cg_frotor / NBBY;
- len = howmany(fs->fs_fpg, NBBY) - start;
- loc = scanc((u_int)len, (u_char *)&cg_blksfree(cgp)[start],
- (u_char *)fragtbl[fs->fs_frag],
- (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
- if (loc == 0) {
- len = start + 1;
- start = 0;
- loc = scanc((u_int)len, (u_char *)&cg_blksfree(cgp)[0],
- (u_char *)fragtbl[fs->fs_frag],
- (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
- assert (loc);
-
- }
- bno = (start + len - loc) * NBBY;
- cgp->cg_frotor = bno;
- /*
- * found the byte in the map
- * sift through the bits to find the selected frag
- */
- for (i = bno + NBBY; bno < i; bno += fs->fs_frag) {
- blk = blkmap(fs, cg_blksfree(cgp), bno);
- blk <<= 1;
- field = around[allocsiz];
- subfield = inside[allocsiz];
- for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) {
- if ((blk & field) == subfield)
- return (bno + pos);
- field <<= 1;
- subfield <<= 1;
- }
- }
- assert (0);
- return (-1);
-}
-
-/*
- * Update the cluster map because of an allocation or free.
- *
- * Cnt == 1 means free; cnt == -1 means allocating.
- */
-static void
-ffs_clusteracct(struct fs *fs,
- struct cg *cgp,
- daddr_t blkno,
- int cnt)
-{
- long *sump;
- u_char *freemapp, *mapp;
- int i, start, end, forw, back, map, bit;
-
- if (fs->fs_contigsumsize <= 0)
- return;
- freemapp = cg_clustersfree(cgp);
- sump = cg_clustersum(cgp);
- /*
- * Allocate or clear the actual block.
- */
- if (cnt > 0)
- setbit(freemapp, blkno);
- else
- clrbit(freemapp, blkno);
- /*
- * Find the size of the cluster going forward.
- */
- start = blkno + 1;
- end = start + fs->fs_contigsumsize;
- if (end >= cgp->cg_nclusterblks)
- end = cgp->cg_nclusterblks;
- mapp = &freemapp[start / NBBY];
- map = *mapp++;
- bit = 1 << (start % NBBY);
- for (i = start; i < end; i++) {
- if ((map & bit) == 0)
- break;
- if ((i & (NBBY - 1)) != (NBBY - 1)) {
- bit <<= 1;
- } else {
- map = *mapp++;
- bit = 1;
- }
- }
- forw = i - start;
- /*
- * Find the size of the cluster going backward.
- */
- start = blkno - 1;
- end = start - fs->fs_contigsumsize;
- if (end < 0)
- end = -1;
- mapp = &freemapp[start / NBBY];
- map = *mapp--;
- bit = 1 << (start % NBBY);
- for (i = start; i > end; i--) {
- if ((map & bit) == 0)
- break;
- if ((i & (NBBY - 1)) != 0) {
- bit >>= 1;
- } else {
- map = *mapp--;
- bit = 1 << (NBBY - 1);
- }
- }
- back = start - i;
- /*
- * Account for old cluster and the possibly new forward and
- * back clusters.
- */
- i = back + forw + 1;
- if (i > fs->fs_contigsumsize)
- i = fs->fs_contigsumsize;
- sump[i] += cnt;
- if (back > 0)
- sump[back] -= cnt;
- if (forw > 0)
- sump[forw] -= cnt;
-}
-
-#if 0
-/*
- * Fserr prints the name of a file system with an error diagnostic.
- *
- * The form of the error message is:
- * fs: error message
- */
-static void
-ffs_fserr(fs, uid, cp)
- struct fs *fs;
- u_int uid;
- char *cp;
-{
-
- log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp);
-}
-#endif