160727d8bSWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1993 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 8df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 9df8bae1dSRodney W. Grimes * are met: 10df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 12df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 14df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1515c377c3SEd Maste * 3. Neither the name of the University nor the names of its contributors 16df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 17df8bae1dSRodney W. Grimes * without specific prior written permission. 18df8bae1dSRodney W. Grimes * 19df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29df8bae1dSRodney W. Grimes * SUCH DAMAGE. 30df8bae1dSRodney W. Grimes * 31996c772fSJohn Dyson * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 32df8bae1dSRodney W. Grimes */ 33df8bae1dSRodney W. Grimes 34f4636c59SDavid E. O'Brien #include <sys/cdefs.h> 35f4636c59SDavid E. O'Brien __FBSDID("$FreeBSD$"); 36f4636c59SDavid E. O'Brien 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38df8bae1dSRodney W. Grimes 39c4473420SPeter Wemm #ifndef _KERNEL 40*dffce215SKirk McKusick #include <stdio.h> 41*dffce215SKirk McKusick #include <string.h> 42*dffce215SKirk McKusick #include <stdlib.h> 43*dffce215SKirk McKusick #include <time.h> 44*dffce215SKirk McKusick #include <sys/errno.h> 45996c772fSJohn Dyson #include <ufs/ufs/dinode.h> 461c85e6a3SKirk McKusick #include <ufs/ffs/fs.h> 47*dffce215SKirk McKusick 48*dffce215SKirk McKusick struct malloc_type; 49*dffce215SKirk McKusick #define UFS_MALLOC(size, type, flags) malloc(size) 50*dffce215SKirk McKusick #define UFS_FREE(ptr, type) free(ptr) 51*dffce215SKirk McKusick #define UFS_TIME time(NULL) 52*dffce215SKirk McKusick 53*dffce215SKirk McKusick #else /* _KERNEL */ 54df8bae1dSRodney W. Grimes #include <sys/systm.h> 551cd52ec3SBruce Evans #include <sys/lock.h> 561c85e6a3SKirk McKusick #include <sys/malloc.h> 571c85e6a3SKirk McKusick #include <sys/mount.h> 58df8bae1dSRodney W. Grimes #include <sys/vnode.h> 599626b608SPoul-Henning Kamp #include <sys/bio.h> 60df8bae1dSRodney W. Grimes #include <sys/buf.h> 6108637435SBruce Evans #include <sys/ucred.h> 6208637435SBruce Evans 63df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h> 64df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h> 651c85e6a3SKirk McKusick #include <ufs/ufs/extattr.h> 661c85e6a3SKirk McKusick #include <ufs/ufs/ufsmount.h> 671c85e6a3SKirk McKusick #include <ufs/ufs/ufs_extern.h> 68996c772fSJohn Dyson #include <ufs/ffs/ffs_extern.h> 691c85e6a3SKirk McKusick #include <ufs/ffs/fs.h> 70df8bae1dSRodney W. Grimes 71*dffce215SKirk McKusick #define UFS_MALLOC(size, type, flags) malloc(size, type, flags) 72*dffce215SKirk McKusick #define UFS_FREE(ptr, type) free(ptr, type) 73*dffce215SKirk McKusick #define UFS_TIME time_second 74*dffce215SKirk McKusick 75df8bae1dSRodney W. Grimes /* 76df8bae1dSRodney W. Grimes * Return buffer with the contents of block "offset" from the beginning of 77df8bae1dSRodney W. Grimes * directory "ip". If "res" is non-zero, fill it in with a pointer to the 78df8bae1dSRodney W. Grimes * remaining space in the directory. 79df8bae1dSRodney W. Grimes */ 80df8bae1dSRodney W. Grimes int 8115c377c3SEd Maste ffs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp) 82df8bae1dSRodney W. Grimes { 83df8bae1dSRodney W. Grimes struct inode *ip; 8405f4ff5dSPoul-Henning Kamp struct fs *fs; 85df8bae1dSRodney W. Grimes struct buf *bp; 861c85e6a3SKirk McKusick ufs_lbn_t lbn; 87df8bae1dSRodney W. Grimes int bsize, error; 88df8bae1dSRodney W. Grimes 89cec0f20cSPoul-Henning Kamp ip = VTOI(vp); 90e1db6897SKonstantin Belousov fs = ITOFS(ip); 91cec0f20cSPoul-Henning Kamp lbn = lblkno(fs, offset); 92df8bae1dSRodney W. Grimes bsize = blksize(fs, ip, lbn); 93df8bae1dSRodney W. Grimes 94cec0f20cSPoul-Henning Kamp *bpp = NULL; 95cec0f20cSPoul-Henning Kamp error = bread(vp, lbn, bsize, NOCRED, &bp); 96c1d9efcbSPoul-Henning Kamp if (error) { 97df8bae1dSRodney W. Grimes brelse(bp); 98df8bae1dSRodney W. Grimes return (error); 99df8bae1dSRodney W. Grimes } 100cec0f20cSPoul-Henning Kamp if (res) 101cec0f20cSPoul-Henning Kamp *res = (char *)bp->b_data + blkoff(fs, offset); 102cec0f20cSPoul-Henning Kamp *bpp = bp; 103df8bae1dSRodney W. Grimes return (0); 104df8bae1dSRodney W. Grimes } 1051c85e6a3SKirk McKusick 1061c85e6a3SKirk McKusick /* 1071c85e6a3SKirk McKusick * Load up the contents of an inode and copy the appropriate pieces 1081c85e6a3SKirk McKusick * to the incore copy. 1091c85e6a3SKirk McKusick */ 1101c85e6a3SKirk McKusick void 11115c377c3SEd Maste ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino) 1121c85e6a3SKirk McKusick { 1131c85e6a3SKirk McKusick 114e1db6897SKonstantin Belousov if (I_IS_UFS1(ip)) { 1151c85e6a3SKirk McKusick *ip->i_din1 = 1161c85e6a3SKirk McKusick *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 1171c85e6a3SKirk McKusick ip->i_mode = ip->i_din1->di_mode; 1181c85e6a3SKirk McKusick ip->i_nlink = ip->i_din1->di_nlink; 1191c85e6a3SKirk McKusick ip->i_size = ip->i_din1->di_size; 1201c85e6a3SKirk McKusick ip->i_flags = ip->i_din1->di_flags; 1211c85e6a3SKirk McKusick ip->i_gen = ip->i_din1->di_gen; 1221c85e6a3SKirk McKusick ip->i_uid = ip->i_din1->di_uid; 1231c85e6a3SKirk McKusick ip->i_gid = ip->i_din1->di_gid; 1241c85e6a3SKirk McKusick } else { 1251c85e6a3SKirk McKusick *ip->i_din2 = 1261c85e6a3SKirk McKusick *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 1271c85e6a3SKirk McKusick ip->i_mode = ip->i_din2->di_mode; 1281c85e6a3SKirk McKusick ip->i_nlink = ip->i_din2->di_nlink; 1291c85e6a3SKirk McKusick ip->i_size = ip->i_din2->di_size; 1301c85e6a3SKirk McKusick ip->i_flags = ip->i_din2->di_flags; 1311c85e6a3SKirk McKusick ip->i_gen = ip->i_din2->di_gen; 1321c85e6a3SKirk McKusick ip->i_uid = ip->i_din2->di_uid; 1331c85e6a3SKirk McKusick ip->i_gid = ip->i_din2->di_gid; 1341c85e6a3SKirk McKusick } 1351c85e6a3SKirk McKusick } 1361c85e6a3SKirk McKusick #endif /* KERNEL */ 137df8bae1dSRodney W. Grimes 138df8bae1dSRodney W. Grimes /* 139*dffce215SKirk McKusick * These are the low-level functions that actually read and write 140*dffce215SKirk McKusick * the superblock and its associated data. 141*dffce215SKirk McKusick */ 142*dffce215SKirk McKusick static off_t sblock_try[] = SBLOCKSEARCH; 143*dffce215SKirk McKusick static int readsuper(void *, struct fs **, off_t, 144*dffce215SKirk McKusick int (*)(void *, off_t, void **, int)); 145*dffce215SKirk McKusick 146*dffce215SKirk McKusick /* 147*dffce215SKirk McKusick * Read a superblock from the devfd device. 148*dffce215SKirk McKusick * 149*dffce215SKirk McKusick * If an alternate superblock is specified, it is read. Otherwise the 150*dffce215SKirk McKusick * set of locations given in the SBLOCKSEARCH list is searched for a 151*dffce215SKirk McKusick * superblock. Memory is allocated for the superblock by the readfunc and 152*dffce215SKirk McKusick * is returned. If filltype is non-NULL, additional memory is allocated 153*dffce215SKirk McKusick * of type filltype and filled in with the superblock summary information. 154*dffce215SKirk McKusick * 155*dffce215SKirk McKusick * If a superblock is found, zero is returned. Otherwise one of the 156*dffce215SKirk McKusick * following error values is returned: 157*dffce215SKirk McKusick * EIO: non-existent or truncated superblock. 158*dffce215SKirk McKusick * EIO: error reading summary information. 159*dffce215SKirk McKusick * ENOENT: no usable known superblock found. 160*dffce215SKirk McKusick * ENOSPC: failed to allocate space for the superblock. 161*dffce215SKirk McKusick * EINVAL: The previous newfs operation on this volume did not complete. 162*dffce215SKirk McKusick * The administrator must complete newfs before using this volume. 163*dffce215SKirk McKusick */ 164*dffce215SKirk McKusick int 165*dffce215SKirk McKusick ffs_sbget(void *devfd, struct fs **fsp, off_t altsuperblock, 166*dffce215SKirk McKusick struct malloc_type *filltype, 167*dffce215SKirk McKusick int (*readfunc)(void *devfd, off_t loc, void **bufp, int size)) 168*dffce215SKirk McKusick { 169*dffce215SKirk McKusick struct fs *fs; 170*dffce215SKirk McKusick int i, ret, size, blks; 171*dffce215SKirk McKusick uint8_t *space; 172*dffce215SKirk McKusick int32_t *lp; 173*dffce215SKirk McKusick char *buf; 174*dffce215SKirk McKusick 175*dffce215SKirk McKusick if (altsuperblock != -1) { 176*dffce215SKirk McKusick if ((ret = readsuper(devfd, fsp, altsuperblock, readfunc)) != 0) 177*dffce215SKirk McKusick return (ret); 178*dffce215SKirk McKusick } else { 179*dffce215SKirk McKusick for (i = 0; sblock_try[i] != -1; i++) { 180*dffce215SKirk McKusick if ((ret = readsuper(devfd, fsp, sblock_try[i], 181*dffce215SKirk McKusick readfunc)) == 0) 182*dffce215SKirk McKusick break; 183*dffce215SKirk McKusick if (ret == ENOENT) 184*dffce215SKirk McKusick continue; 185*dffce215SKirk McKusick return (ret); 186*dffce215SKirk McKusick } 187*dffce215SKirk McKusick if (sblock_try[i] == -1) 188*dffce215SKirk McKusick return (ENOENT); 189*dffce215SKirk McKusick } 190*dffce215SKirk McKusick /* 191*dffce215SKirk McKusick * If not filling in summary information, NULL out fs_csp and return. 192*dffce215SKirk McKusick */ 193*dffce215SKirk McKusick fs = *fsp; 194*dffce215SKirk McKusick if (filltype == NULL) { 195*dffce215SKirk McKusick fs->fs_csp = NULL; 196*dffce215SKirk McKusick return (0); 197*dffce215SKirk McKusick } 198*dffce215SKirk McKusick /* 199*dffce215SKirk McKusick * Read in the superblock summary information. 200*dffce215SKirk McKusick */ 201*dffce215SKirk McKusick size = fs->fs_cssize; 202*dffce215SKirk McKusick blks = howmany(size, fs->fs_fsize); 203*dffce215SKirk McKusick if (fs->fs_contigsumsize > 0) 204*dffce215SKirk McKusick size += fs->fs_ncg * sizeof(int32_t); 205*dffce215SKirk McKusick size += fs->fs_ncg * sizeof(u_int8_t); 206*dffce215SKirk McKusick space = UFS_MALLOC(size, filltype, M_WAITOK); 207*dffce215SKirk McKusick fs->fs_csp = (struct csum *)space; 208*dffce215SKirk McKusick for (i = 0; i < blks; i += fs->fs_frag) { 209*dffce215SKirk McKusick size = fs->fs_bsize; 210*dffce215SKirk McKusick if (i + fs->fs_frag > blks) 211*dffce215SKirk McKusick size = (blks - i) * fs->fs_fsize; 212*dffce215SKirk McKusick ret = (*readfunc)(devfd, 213*dffce215SKirk McKusick dbtob(fsbtodb(fs, fs->fs_csaddr + i)), (void **)&buf, size); 214*dffce215SKirk McKusick if (ret) { 215*dffce215SKirk McKusick UFS_FREE(fs->fs_csp, filltype); 216*dffce215SKirk McKusick fs->fs_csp = NULL; 217*dffce215SKirk McKusick return (ret); 218*dffce215SKirk McKusick } 219*dffce215SKirk McKusick memcpy(space, buf, size); 220*dffce215SKirk McKusick UFS_FREE(buf, filltype); 221*dffce215SKirk McKusick space += size; 222*dffce215SKirk McKusick } 223*dffce215SKirk McKusick if (fs->fs_contigsumsize > 0) { 224*dffce215SKirk McKusick fs->fs_maxcluster = lp = (int32_t *)space; 225*dffce215SKirk McKusick for (i = 0; i < fs->fs_ncg; i++) 226*dffce215SKirk McKusick *lp++ = fs->fs_contigsumsize; 227*dffce215SKirk McKusick space = (uint8_t *)lp; 228*dffce215SKirk McKusick } 229*dffce215SKirk McKusick size = fs->fs_ncg * sizeof(u_int8_t); 230*dffce215SKirk McKusick fs->fs_contigdirs = (u_int8_t *)space; 231*dffce215SKirk McKusick bzero(fs->fs_contigdirs, size); 232*dffce215SKirk McKusick return (0); 233*dffce215SKirk McKusick } 234*dffce215SKirk McKusick 235*dffce215SKirk McKusick /* 236*dffce215SKirk McKusick * Try to read a superblock from the location specified by sblockloc. 237*dffce215SKirk McKusick * Return zero on success or an errno on failure. 238*dffce215SKirk McKusick */ 239*dffce215SKirk McKusick static int 240*dffce215SKirk McKusick readsuper(void *devfd, struct fs **fsp, off_t sblockloc, 241*dffce215SKirk McKusick int (*readfunc)(void *devfd, off_t loc, void **bufp, int size)) 242*dffce215SKirk McKusick { 243*dffce215SKirk McKusick struct fs *fs; 244*dffce215SKirk McKusick int error; 245*dffce215SKirk McKusick 246*dffce215SKirk McKusick error = (*readfunc)(devfd, sblockloc, (void **)fsp, SBLOCKSIZE); 247*dffce215SKirk McKusick if (error != 0) 248*dffce215SKirk McKusick return (error); 249*dffce215SKirk McKusick fs = *fsp; 250*dffce215SKirk McKusick if (fs->fs_magic == FS_BAD_MAGIC) 251*dffce215SKirk McKusick return (EINVAL); 252*dffce215SKirk McKusick if (((fs->fs_magic == FS_UFS1_MAGIC && sblockloc <= SBLOCK_UFS1) || 253*dffce215SKirk McKusick (fs->fs_magic == FS_UFS2_MAGIC && 254*dffce215SKirk McKusick sblockloc == fs->fs_sblockloc)) && 255*dffce215SKirk McKusick fs->fs_ncg >= 1 && 256*dffce215SKirk McKusick fs->fs_bsize >= MINBSIZE && 257*dffce215SKirk McKusick fs->fs_bsize <= MAXBSIZE && 258*dffce215SKirk McKusick fs->fs_bsize >= roundup(sizeof(struct fs), DEV_BSIZE)) { 259*dffce215SKirk McKusick /* Have to set for old filesystems that predate this field */ 260*dffce215SKirk McKusick fs->fs_sblockactualloc = sblockloc; 261*dffce215SKirk McKusick return (0); 262*dffce215SKirk McKusick } 263*dffce215SKirk McKusick return (ENOENT); 264*dffce215SKirk McKusick } 265*dffce215SKirk McKusick 266*dffce215SKirk McKusick /* 267*dffce215SKirk McKusick * Write a superblock to the devfd device from the memory pointed to by fs. 268*dffce215SKirk McKusick * Write out the superblock summary information if it is present. 269*dffce215SKirk McKusick * 270*dffce215SKirk McKusick * If the write is successful, zero is returned. Otherwise one of the 271*dffce215SKirk McKusick * following error values is returned: 272*dffce215SKirk McKusick * EIO: failed to write superblock. 273*dffce215SKirk McKusick * EIO: failed to write superblock summary information. 274*dffce215SKirk McKusick */ 275*dffce215SKirk McKusick int 276*dffce215SKirk McKusick ffs_sbput(void *devfd, struct fs *fs, off_t loc, 277*dffce215SKirk McKusick int (*writefunc)(void *devfd, off_t loc, void *buf, int size)) 278*dffce215SKirk McKusick { 279*dffce215SKirk McKusick int i, error, blks, size; 280*dffce215SKirk McKusick uint8_t *space; 281*dffce215SKirk McKusick 282*dffce215SKirk McKusick /* 283*dffce215SKirk McKusick * If there is summary information, write it first, so if there 284*dffce215SKirk McKusick * is an error, the superblock will not be marked as clean. 285*dffce215SKirk McKusick */ 286*dffce215SKirk McKusick if (fs->fs_csp != NULL) { 287*dffce215SKirk McKusick blks = howmany(fs->fs_cssize, fs->fs_fsize); 288*dffce215SKirk McKusick space = (uint8_t *)fs->fs_csp; 289*dffce215SKirk McKusick for (i = 0; i < blks; i += fs->fs_frag) { 290*dffce215SKirk McKusick size = fs->fs_bsize; 291*dffce215SKirk McKusick if (i + fs->fs_frag > blks) 292*dffce215SKirk McKusick size = (blks - i) * fs->fs_fsize; 293*dffce215SKirk McKusick if ((error = (*writefunc)(devfd, 294*dffce215SKirk McKusick dbtob(fsbtodb(fs, fs->fs_csaddr + i)), 295*dffce215SKirk McKusick space, size)) != 0) 296*dffce215SKirk McKusick return (error); 297*dffce215SKirk McKusick space += size; 298*dffce215SKirk McKusick } 299*dffce215SKirk McKusick } 300*dffce215SKirk McKusick fs->fs_fmod = 0; 301*dffce215SKirk McKusick fs->fs_time = UFS_TIME; 302*dffce215SKirk McKusick if ((error = (*writefunc)(devfd, loc, fs, fs->fs_sbsize)) != 0) 303*dffce215SKirk McKusick return (error); 304*dffce215SKirk McKusick return (0); 305*dffce215SKirk McKusick } 306*dffce215SKirk McKusick 307*dffce215SKirk McKusick /* 308df8bae1dSRodney W. Grimes * Update the frsum fields to reflect addition or deletion 309df8bae1dSRodney W. Grimes * of some frags. 310df8bae1dSRodney W. Grimes */ 311df8bae1dSRodney W. Grimes void 31215c377c3SEd Maste ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt) 313df8bae1dSRodney W. Grimes { 314df8bae1dSRodney W. Grimes int inblk; 31505f4ff5dSPoul-Henning Kamp int field, subfield; 31605f4ff5dSPoul-Henning Kamp int siz, pos; 317df8bae1dSRodney W. Grimes 318df8bae1dSRodney W. Grimes inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 319df8bae1dSRodney W. Grimes fragmap <<= 1; 320df8bae1dSRodney W. Grimes for (siz = 1; siz < fs->fs_frag; siz++) { 321df8bae1dSRodney W. Grimes if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 322df8bae1dSRodney W. Grimes continue; 323df8bae1dSRodney W. Grimes field = around[siz]; 324df8bae1dSRodney W. Grimes subfield = inside[siz]; 325df8bae1dSRodney W. Grimes for (pos = siz; pos <= fs->fs_frag; pos++) { 326df8bae1dSRodney W. Grimes if ((fragmap & field) == subfield) { 327df8bae1dSRodney W. Grimes fraglist[siz] += cnt; 328df8bae1dSRodney W. Grimes pos += siz; 329df8bae1dSRodney W. Grimes field <<= siz; 330df8bae1dSRodney W. Grimes subfield <<= siz; 331df8bae1dSRodney W. Grimes } 332df8bae1dSRodney W. Grimes field <<= 1; 333df8bae1dSRodney W. Grimes subfield <<= 1; 334df8bae1dSRodney W. Grimes } 335df8bae1dSRodney W. Grimes } 336df8bae1dSRodney W. Grimes } 337df8bae1dSRodney W. Grimes 338df8bae1dSRodney W. Grimes /* 339df8bae1dSRodney W. Grimes * block operations 340df8bae1dSRodney W. Grimes * 341df8bae1dSRodney W. Grimes * check if a block is available 342df8bae1dSRodney W. Grimes */ 343df8bae1dSRodney W. Grimes int 34415c377c3SEd Maste ffs_isblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h) 345df8bae1dSRodney W. Grimes { 346df8bae1dSRodney W. Grimes unsigned char mask; 347df8bae1dSRodney W. Grimes 348df8bae1dSRodney W. Grimes switch ((int)fs->fs_frag) { 349df8bae1dSRodney W. Grimes case 8: 350df8bae1dSRodney W. Grimes return (cp[h] == 0xff); 351df8bae1dSRodney W. Grimes case 4: 352df8bae1dSRodney W. Grimes mask = 0x0f << ((h & 0x1) << 2); 353df8bae1dSRodney W. Grimes return ((cp[h >> 1] & mask) == mask); 354df8bae1dSRodney W. Grimes case 2: 355df8bae1dSRodney W. Grimes mask = 0x03 << ((h & 0x3) << 1); 356df8bae1dSRodney W. Grimes return ((cp[h >> 2] & mask) == mask); 357df8bae1dSRodney W. Grimes case 1: 358df8bae1dSRodney W. Grimes mask = 0x01 << (h & 0x7); 359df8bae1dSRodney W. Grimes return ((cp[h >> 3] & mask) == mask); 360df8bae1dSRodney W. Grimes default: 361113db2ddSJeff Roberson #ifdef _KERNEL 362df8bae1dSRodney W. Grimes panic("ffs_isblock"); 363113db2ddSJeff Roberson #endif 364113db2ddSJeff Roberson break; 365113db2ddSJeff Roberson } 366113db2ddSJeff Roberson return (0); 367113db2ddSJeff Roberson } 368113db2ddSJeff Roberson 369113db2ddSJeff Roberson /* 370113db2ddSJeff Roberson * check if a block is free 371113db2ddSJeff Roberson */ 372113db2ddSJeff Roberson int 37315c377c3SEd Maste ffs_isfreeblock(struct fs *fs, u_char *cp, ufs1_daddr_t h) 374113db2ddSJeff Roberson { 375113db2ddSJeff Roberson 376113db2ddSJeff Roberson switch ((int)fs->fs_frag) { 377113db2ddSJeff Roberson case 8: 378113db2ddSJeff Roberson return (cp[h] == 0); 379113db2ddSJeff Roberson case 4: 380113db2ddSJeff Roberson return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); 381113db2ddSJeff Roberson case 2: 382113db2ddSJeff Roberson return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); 383113db2ddSJeff Roberson case 1: 384113db2ddSJeff Roberson return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); 385113db2ddSJeff Roberson default: 386113db2ddSJeff Roberson #ifdef _KERNEL 387113db2ddSJeff Roberson panic("ffs_isfreeblock"); 388113db2ddSJeff Roberson #endif 389113db2ddSJeff Roberson break; 390df8bae1dSRodney W. Grimes } 391589c7af9SKirk McKusick return (0); 392df8bae1dSRodney W. Grimes } 393df8bae1dSRodney W. Grimes 394df8bae1dSRodney W. Grimes /* 395df8bae1dSRodney W. Grimes * take a block out of the map 396df8bae1dSRodney W. Grimes */ 397df8bae1dSRodney W. Grimes void 39815c377c3SEd Maste ffs_clrblock(struct fs *fs, u_char *cp, ufs1_daddr_t h) 399df8bae1dSRodney W. Grimes { 400df8bae1dSRodney W. Grimes 401df8bae1dSRodney W. Grimes switch ((int)fs->fs_frag) { 402df8bae1dSRodney W. Grimes case 8: 403df8bae1dSRodney W. Grimes cp[h] = 0; 404df8bae1dSRodney W. Grimes return; 405df8bae1dSRodney W. Grimes case 4: 406df8bae1dSRodney W. Grimes cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 407df8bae1dSRodney W. Grimes return; 408df8bae1dSRodney W. Grimes case 2: 409df8bae1dSRodney W. Grimes cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 410df8bae1dSRodney W. Grimes return; 411df8bae1dSRodney W. Grimes case 1: 412df8bae1dSRodney W. Grimes cp[h >> 3] &= ~(0x01 << (h & 0x7)); 413df8bae1dSRodney W. Grimes return; 414df8bae1dSRodney W. Grimes default: 415113db2ddSJeff Roberson #ifdef _KERNEL 416df8bae1dSRodney W. Grimes panic("ffs_clrblock"); 417113db2ddSJeff Roberson #endif 418113db2ddSJeff Roberson break; 419df8bae1dSRodney W. Grimes } 420df8bae1dSRodney W. Grimes } 421df8bae1dSRodney W. Grimes 422df8bae1dSRodney W. Grimes /* 423df8bae1dSRodney W. Grimes * put a block into the map 424df8bae1dSRodney W. Grimes */ 425df8bae1dSRodney W. Grimes void 42615c377c3SEd Maste ffs_setblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h) 427df8bae1dSRodney W. Grimes { 428df8bae1dSRodney W. Grimes 429df8bae1dSRodney W. Grimes switch ((int)fs->fs_frag) { 430df8bae1dSRodney W. Grimes 431df8bae1dSRodney W. Grimes case 8: 432df8bae1dSRodney W. Grimes cp[h] = 0xff; 433df8bae1dSRodney W. Grimes return; 434df8bae1dSRodney W. Grimes case 4: 435df8bae1dSRodney W. Grimes cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 436df8bae1dSRodney W. Grimes return; 437df8bae1dSRodney W. Grimes case 2: 438df8bae1dSRodney W. Grimes cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 439df8bae1dSRodney W. Grimes return; 440df8bae1dSRodney W. Grimes case 1: 441df8bae1dSRodney W. Grimes cp[h >> 3] |= (0x01 << (h & 0x7)); 442df8bae1dSRodney W. Grimes return; 443df8bae1dSRodney W. Grimes default: 444113db2ddSJeff Roberson #ifdef _KERNEL 445df8bae1dSRodney W. Grimes panic("ffs_setblock"); 446113db2ddSJeff Roberson #endif 447113db2ddSJeff Roberson break; 448df8bae1dSRodney W. Grimes } 449df8bae1dSRodney W. Grimes } 450113db2ddSJeff Roberson 451113db2ddSJeff Roberson /* 452113db2ddSJeff Roberson * Update the cluster map because of an allocation or free. 453113db2ddSJeff Roberson * 454113db2ddSJeff Roberson * Cnt == 1 means free; cnt == -1 means allocating. 455113db2ddSJeff Roberson */ 456113db2ddSJeff Roberson void 45715c377c3SEd Maste ffs_clusteracct(struct fs *fs, struct cg *cgp, ufs1_daddr_t blkno, int cnt) 458113db2ddSJeff Roberson { 459113db2ddSJeff Roberson int32_t *sump; 460113db2ddSJeff Roberson int32_t *lp; 461113db2ddSJeff Roberson u_char *freemapp, *mapp; 462113db2ddSJeff Roberson int i, start, end, forw, back, map, bit; 463113db2ddSJeff Roberson 464113db2ddSJeff Roberson if (fs->fs_contigsumsize <= 0) 465113db2ddSJeff Roberson return; 466113db2ddSJeff Roberson freemapp = cg_clustersfree(cgp); 467113db2ddSJeff Roberson sump = cg_clustersum(cgp); 468113db2ddSJeff Roberson /* 469113db2ddSJeff Roberson * Allocate or clear the actual block. 470113db2ddSJeff Roberson */ 471113db2ddSJeff Roberson if (cnt > 0) 472113db2ddSJeff Roberson setbit(freemapp, blkno); 473113db2ddSJeff Roberson else 474113db2ddSJeff Roberson clrbit(freemapp, blkno); 475113db2ddSJeff Roberson /* 476113db2ddSJeff Roberson * Find the size of the cluster going forward. 477113db2ddSJeff Roberson */ 478113db2ddSJeff Roberson start = blkno + 1; 479113db2ddSJeff Roberson end = start + fs->fs_contigsumsize; 480113db2ddSJeff Roberson if (end >= cgp->cg_nclusterblks) 481113db2ddSJeff Roberson end = cgp->cg_nclusterblks; 482113db2ddSJeff Roberson mapp = &freemapp[start / NBBY]; 483113db2ddSJeff Roberson map = *mapp++; 484113db2ddSJeff Roberson bit = 1 << (start % NBBY); 485113db2ddSJeff Roberson for (i = start; i < end; i++) { 486113db2ddSJeff Roberson if ((map & bit) == 0) 487113db2ddSJeff Roberson break; 488113db2ddSJeff Roberson if ((i & (NBBY - 1)) != (NBBY - 1)) { 489113db2ddSJeff Roberson bit <<= 1; 490113db2ddSJeff Roberson } else { 491113db2ddSJeff Roberson map = *mapp++; 492113db2ddSJeff Roberson bit = 1; 493113db2ddSJeff Roberson } 494113db2ddSJeff Roberson } 495113db2ddSJeff Roberson forw = i - start; 496113db2ddSJeff Roberson /* 497113db2ddSJeff Roberson * Find the size of the cluster going backward. 498113db2ddSJeff Roberson */ 499113db2ddSJeff Roberson start = blkno - 1; 500113db2ddSJeff Roberson end = start - fs->fs_contigsumsize; 501113db2ddSJeff Roberson if (end < 0) 502113db2ddSJeff Roberson end = -1; 503113db2ddSJeff Roberson mapp = &freemapp[start / NBBY]; 504113db2ddSJeff Roberson map = *mapp--; 505113db2ddSJeff Roberson bit = 1 << (start % NBBY); 506113db2ddSJeff Roberson for (i = start; i > end; i--) { 507113db2ddSJeff Roberson if ((map & bit) == 0) 508113db2ddSJeff Roberson break; 509113db2ddSJeff Roberson if ((i & (NBBY - 1)) != 0) { 510113db2ddSJeff Roberson bit >>= 1; 511113db2ddSJeff Roberson } else { 512113db2ddSJeff Roberson map = *mapp--; 513113db2ddSJeff Roberson bit = 1 << (NBBY - 1); 514113db2ddSJeff Roberson } 515113db2ddSJeff Roberson } 516113db2ddSJeff Roberson back = start - i; 517113db2ddSJeff Roberson /* 518113db2ddSJeff Roberson * Account for old cluster and the possibly new forward and 519113db2ddSJeff Roberson * back clusters. 520113db2ddSJeff Roberson */ 521113db2ddSJeff Roberson i = back + forw + 1; 522113db2ddSJeff Roberson if (i > fs->fs_contigsumsize) 523113db2ddSJeff Roberson i = fs->fs_contigsumsize; 524113db2ddSJeff Roberson sump[i] += cnt; 525113db2ddSJeff Roberson if (back > 0) 526113db2ddSJeff Roberson sump[back] -= cnt; 527113db2ddSJeff Roberson if (forw > 0) 528113db2ddSJeff Roberson sump[forw] -= cnt; 529113db2ddSJeff Roberson /* 530113db2ddSJeff Roberson * Update cluster summary information. 531113db2ddSJeff Roberson */ 532113db2ddSJeff Roberson lp = &sump[fs->fs_contigsumsize]; 533113db2ddSJeff Roberson for (i = fs->fs_contigsumsize; i > 0; i--) 534113db2ddSJeff Roberson if (*lp-- > 0) 535113db2ddSJeff Roberson break; 536113db2ddSJeff Roberson fs->fs_maxcluster[cgp->cg_cgx] = i; 537113db2ddSJeff Roberson } 538