160727d8bSWarner Losh /*- 2*51369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*51369649SPedro 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 40996c772fSJohn Dyson #include <ufs/ufs/dinode.h> 411c85e6a3SKirk McKusick #include <ufs/ffs/fs.h> 42996c772fSJohn Dyson #else 43df8bae1dSRodney W. Grimes #include <sys/systm.h> 441cd52ec3SBruce Evans #include <sys/lock.h> 451c85e6a3SKirk McKusick #include <sys/malloc.h> 461c85e6a3SKirk McKusick #include <sys/mount.h> 47df8bae1dSRodney W. Grimes #include <sys/vnode.h> 489626b608SPoul-Henning Kamp #include <sys/bio.h> 49df8bae1dSRodney W. Grimes #include <sys/buf.h> 5008637435SBruce Evans #include <sys/ucred.h> 5108637435SBruce Evans 52df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h> 53df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h> 541c85e6a3SKirk McKusick #include <ufs/ufs/extattr.h> 551c85e6a3SKirk McKusick #include <ufs/ufs/ufsmount.h> 561c85e6a3SKirk McKusick #include <ufs/ufs/ufs_extern.h> 57996c772fSJohn Dyson #include <ufs/ffs/ffs_extern.h> 581c85e6a3SKirk McKusick #include <ufs/ffs/fs.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes /* 61df8bae1dSRodney W. Grimes * Return buffer with the contents of block "offset" from the beginning of 62df8bae1dSRodney W. Grimes * directory "ip". If "res" is non-zero, fill it in with a pointer to the 63df8bae1dSRodney W. Grimes * remaining space in the directory. 64df8bae1dSRodney W. Grimes */ 65df8bae1dSRodney W. Grimes int 6615c377c3SEd Maste ffs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp) 67df8bae1dSRodney W. Grimes { 68df8bae1dSRodney W. Grimes struct inode *ip; 6905f4ff5dSPoul-Henning Kamp struct fs *fs; 70df8bae1dSRodney W. Grimes struct buf *bp; 711c85e6a3SKirk McKusick ufs_lbn_t lbn; 72df8bae1dSRodney W. Grimes int bsize, error; 73df8bae1dSRodney W. Grimes 74cec0f20cSPoul-Henning Kamp ip = VTOI(vp); 75e1db6897SKonstantin Belousov fs = ITOFS(ip); 76cec0f20cSPoul-Henning Kamp lbn = lblkno(fs, offset); 77df8bae1dSRodney W. Grimes bsize = blksize(fs, ip, lbn); 78df8bae1dSRodney W. Grimes 79cec0f20cSPoul-Henning Kamp *bpp = NULL; 80cec0f20cSPoul-Henning Kamp error = bread(vp, lbn, bsize, NOCRED, &bp); 81c1d9efcbSPoul-Henning Kamp if (error) { 82df8bae1dSRodney W. Grimes brelse(bp); 83df8bae1dSRodney W. Grimes return (error); 84df8bae1dSRodney W. Grimes } 85cec0f20cSPoul-Henning Kamp if (res) 86cec0f20cSPoul-Henning Kamp *res = (char *)bp->b_data + blkoff(fs, offset); 87cec0f20cSPoul-Henning Kamp *bpp = bp; 88df8bae1dSRodney W. Grimes return (0); 89df8bae1dSRodney W. Grimes } 901c85e6a3SKirk McKusick 911c85e6a3SKirk McKusick /* 921c85e6a3SKirk McKusick * Load up the contents of an inode and copy the appropriate pieces 931c85e6a3SKirk McKusick * to the incore copy. 941c85e6a3SKirk McKusick */ 951c85e6a3SKirk McKusick void 9615c377c3SEd Maste ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino) 971c85e6a3SKirk McKusick { 981c85e6a3SKirk McKusick 99e1db6897SKonstantin Belousov if (I_IS_UFS1(ip)) { 1001c85e6a3SKirk McKusick *ip->i_din1 = 1011c85e6a3SKirk McKusick *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 1021c85e6a3SKirk McKusick ip->i_mode = ip->i_din1->di_mode; 1031c85e6a3SKirk McKusick ip->i_nlink = ip->i_din1->di_nlink; 1041c85e6a3SKirk McKusick ip->i_size = ip->i_din1->di_size; 1051c85e6a3SKirk McKusick ip->i_flags = ip->i_din1->di_flags; 1061c85e6a3SKirk McKusick ip->i_gen = ip->i_din1->di_gen; 1071c85e6a3SKirk McKusick ip->i_uid = ip->i_din1->di_uid; 1081c85e6a3SKirk McKusick ip->i_gid = ip->i_din1->di_gid; 1091c85e6a3SKirk McKusick } else { 1101c85e6a3SKirk McKusick *ip->i_din2 = 1111c85e6a3SKirk McKusick *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 1121c85e6a3SKirk McKusick ip->i_mode = ip->i_din2->di_mode; 1131c85e6a3SKirk McKusick ip->i_nlink = ip->i_din2->di_nlink; 1141c85e6a3SKirk McKusick ip->i_size = ip->i_din2->di_size; 1151c85e6a3SKirk McKusick ip->i_flags = ip->i_din2->di_flags; 1161c85e6a3SKirk McKusick ip->i_gen = ip->i_din2->di_gen; 1171c85e6a3SKirk McKusick ip->i_uid = ip->i_din2->di_uid; 1181c85e6a3SKirk McKusick ip->i_gid = ip->i_din2->di_gid; 1191c85e6a3SKirk McKusick } 1201c85e6a3SKirk McKusick } 1211c85e6a3SKirk McKusick #endif /* KERNEL */ 122df8bae1dSRodney W. Grimes 123df8bae1dSRodney W. Grimes /* 124df8bae1dSRodney W. Grimes * Update the frsum fields to reflect addition or deletion 125df8bae1dSRodney W. Grimes * of some frags. 126df8bae1dSRodney W. Grimes */ 127df8bae1dSRodney W. Grimes void 12815c377c3SEd Maste ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt) 129df8bae1dSRodney W. Grimes { 130df8bae1dSRodney W. Grimes int inblk; 13105f4ff5dSPoul-Henning Kamp int field, subfield; 13205f4ff5dSPoul-Henning Kamp int siz, pos; 133df8bae1dSRodney W. Grimes 134df8bae1dSRodney W. Grimes inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 135df8bae1dSRodney W. Grimes fragmap <<= 1; 136df8bae1dSRodney W. Grimes for (siz = 1; siz < fs->fs_frag; siz++) { 137df8bae1dSRodney W. Grimes if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 138df8bae1dSRodney W. Grimes continue; 139df8bae1dSRodney W. Grimes field = around[siz]; 140df8bae1dSRodney W. Grimes subfield = inside[siz]; 141df8bae1dSRodney W. Grimes for (pos = siz; pos <= fs->fs_frag; pos++) { 142df8bae1dSRodney W. Grimes if ((fragmap & field) == subfield) { 143df8bae1dSRodney W. Grimes fraglist[siz] += cnt; 144df8bae1dSRodney W. Grimes pos += siz; 145df8bae1dSRodney W. Grimes field <<= siz; 146df8bae1dSRodney W. Grimes subfield <<= siz; 147df8bae1dSRodney W. Grimes } 148df8bae1dSRodney W. Grimes field <<= 1; 149df8bae1dSRodney W. Grimes subfield <<= 1; 150df8bae1dSRodney W. Grimes } 151df8bae1dSRodney W. Grimes } 152df8bae1dSRodney W. Grimes } 153df8bae1dSRodney W. Grimes 154df8bae1dSRodney W. Grimes /* 155df8bae1dSRodney W. Grimes * block operations 156df8bae1dSRodney W. Grimes * 157df8bae1dSRodney W. Grimes * check if a block is available 158df8bae1dSRodney W. Grimes */ 159df8bae1dSRodney W. Grimes int 16015c377c3SEd Maste ffs_isblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h) 161df8bae1dSRodney W. Grimes { 162df8bae1dSRodney W. Grimes unsigned char mask; 163df8bae1dSRodney W. Grimes 164df8bae1dSRodney W. Grimes switch ((int)fs->fs_frag) { 165df8bae1dSRodney W. Grimes case 8: 166df8bae1dSRodney W. Grimes return (cp[h] == 0xff); 167df8bae1dSRodney W. Grimes case 4: 168df8bae1dSRodney W. Grimes mask = 0x0f << ((h & 0x1) << 2); 169df8bae1dSRodney W. Grimes return ((cp[h >> 1] & mask) == mask); 170df8bae1dSRodney W. Grimes case 2: 171df8bae1dSRodney W. Grimes mask = 0x03 << ((h & 0x3) << 1); 172df8bae1dSRodney W. Grimes return ((cp[h >> 2] & mask) == mask); 173df8bae1dSRodney W. Grimes case 1: 174df8bae1dSRodney W. Grimes mask = 0x01 << (h & 0x7); 175df8bae1dSRodney W. Grimes return ((cp[h >> 3] & mask) == mask); 176df8bae1dSRodney W. Grimes default: 177113db2ddSJeff Roberson #ifdef _KERNEL 178df8bae1dSRodney W. Grimes panic("ffs_isblock"); 179113db2ddSJeff Roberson #endif 180113db2ddSJeff Roberson break; 181113db2ddSJeff Roberson } 182113db2ddSJeff Roberson return (0); 183113db2ddSJeff Roberson } 184113db2ddSJeff Roberson 185113db2ddSJeff Roberson /* 186113db2ddSJeff Roberson * check if a block is free 187113db2ddSJeff Roberson */ 188113db2ddSJeff Roberson int 18915c377c3SEd Maste ffs_isfreeblock(struct fs *fs, u_char *cp, ufs1_daddr_t h) 190113db2ddSJeff Roberson { 191113db2ddSJeff Roberson 192113db2ddSJeff Roberson switch ((int)fs->fs_frag) { 193113db2ddSJeff Roberson case 8: 194113db2ddSJeff Roberson return (cp[h] == 0); 195113db2ddSJeff Roberson case 4: 196113db2ddSJeff Roberson return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); 197113db2ddSJeff Roberson case 2: 198113db2ddSJeff Roberson return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); 199113db2ddSJeff Roberson case 1: 200113db2ddSJeff Roberson return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); 201113db2ddSJeff Roberson default: 202113db2ddSJeff Roberson #ifdef _KERNEL 203113db2ddSJeff Roberson panic("ffs_isfreeblock"); 204113db2ddSJeff Roberson #endif 205113db2ddSJeff Roberson break; 206df8bae1dSRodney W. Grimes } 207589c7af9SKirk McKusick return (0); 208df8bae1dSRodney W. Grimes } 209df8bae1dSRodney W. Grimes 210df8bae1dSRodney W. Grimes /* 211df8bae1dSRodney W. Grimes * take a block out of the map 212df8bae1dSRodney W. Grimes */ 213df8bae1dSRodney W. Grimes void 21415c377c3SEd Maste ffs_clrblock(struct fs *fs, u_char *cp, ufs1_daddr_t h) 215df8bae1dSRodney W. Grimes { 216df8bae1dSRodney W. Grimes 217df8bae1dSRodney W. Grimes switch ((int)fs->fs_frag) { 218df8bae1dSRodney W. Grimes case 8: 219df8bae1dSRodney W. Grimes cp[h] = 0; 220df8bae1dSRodney W. Grimes return; 221df8bae1dSRodney W. Grimes case 4: 222df8bae1dSRodney W. Grimes cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 223df8bae1dSRodney W. Grimes return; 224df8bae1dSRodney W. Grimes case 2: 225df8bae1dSRodney W. Grimes cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 226df8bae1dSRodney W. Grimes return; 227df8bae1dSRodney W. Grimes case 1: 228df8bae1dSRodney W. Grimes cp[h >> 3] &= ~(0x01 << (h & 0x7)); 229df8bae1dSRodney W. Grimes return; 230df8bae1dSRodney W. Grimes default: 231113db2ddSJeff Roberson #ifdef _KERNEL 232df8bae1dSRodney W. Grimes panic("ffs_clrblock"); 233113db2ddSJeff Roberson #endif 234113db2ddSJeff Roberson break; 235df8bae1dSRodney W. Grimes } 236df8bae1dSRodney W. Grimes } 237df8bae1dSRodney W. Grimes 238df8bae1dSRodney W. Grimes /* 239df8bae1dSRodney W. Grimes * put a block into the map 240df8bae1dSRodney W. Grimes */ 241df8bae1dSRodney W. Grimes void 24215c377c3SEd Maste ffs_setblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h) 243df8bae1dSRodney W. Grimes { 244df8bae1dSRodney W. Grimes 245df8bae1dSRodney W. Grimes switch ((int)fs->fs_frag) { 246df8bae1dSRodney W. Grimes 247df8bae1dSRodney W. Grimes case 8: 248df8bae1dSRodney W. Grimes cp[h] = 0xff; 249df8bae1dSRodney W. Grimes return; 250df8bae1dSRodney W. Grimes case 4: 251df8bae1dSRodney W. Grimes cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 252df8bae1dSRodney W. Grimes return; 253df8bae1dSRodney W. Grimes case 2: 254df8bae1dSRodney W. Grimes cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 255df8bae1dSRodney W. Grimes return; 256df8bae1dSRodney W. Grimes case 1: 257df8bae1dSRodney W. Grimes cp[h >> 3] |= (0x01 << (h & 0x7)); 258df8bae1dSRodney W. Grimes return; 259df8bae1dSRodney W. Grimes default: 260113db2ddSJeff Roberson #ifdef _KERNEL 261df8bae1dSRodney W. Grimes panic("ffs_setblock"); 262113db2ddSJeff Roberson #endif 263113db2ddSJeff Roberson break; 264df8bae1dSRodney W. Grimes } 265df8bae1dSRodney W. Grimes } 266113db2ddSJeff Roberson 267113db2ddSJeff Roberson /* 268113db2ddSJeff Roberson * Update the cluster map because of an allocation or free. 269113db2ddSJeff Roberson * 270113db2ddSJeff Roberson * Cnt == 1 means free; cnt == -1 means allocating. 271113db2ddSJeff Roberson */ 272113db2ddSJeff Roberson void 27315c377c3SEd Maste ffs_clusteracct(struct fs *fs, struct cg *cgp, ufs1_daddr_t blkno, int cnt) 274113db2ddSJeff Roberson { 275113db2ddSJeff Roberson int32_t *sump; 276113db2ddSJeff Roberson int32_t *lp; 277113db2ddSJeff Roberson u_char *freemapp, *mapp; 278113db2ddSJeff Roberson int i, start, end, forw, back, map, bit; 279113db2ddSJeff Roberson 280113db2ddSJeff Roberson if (fs->fs_contigsumsize <= 0) 281113db2ddSJeff Roberson return; 282113db2ddSJeff Roberson freemapp = cg_clustersfree(cgp); 283113db2ddSJeff Roberson sump = cg_clustersum(cgp); 284113db2ddSJeff Roberson /* 285113db2ddSJeff Roberson * Allocate or clear the actual block. 286113db2ddSJeff Roberson */ 287113db2ddSJeff Roberson if (cnt > 0) 288113db2ddSJeff Roberson setbit(freemapp, blkno); 289113db2ddSJeff Roberson else 290113db2ddSJeff Roberson clrbit(freemapp, blkno); 291113db2ddSJeff Roberson /* 292113db2ddSJeff Roberson * Find the size of the cluster going forward. 293113db2ddSJeff Roberson */ 294113db2ddSJeff Roberson start = blkno + 1; 295113db2ddSJeff Roberson end = start + fs->fs_contigsumsize; 296113db2ddSJeff Roberson if (end >= cgp->cg_nclusterblks) 297113db2ddSJeff Roberson end = cgp->cg_nclusterblks; 298113db2ddSJeff Roberson mapp = &freemapp[start / NBBY]; 299113db2ddSJeff Roberson map = *mapp++; 300113db2ddSJeff Roberson bit = 1 << (start % NBBY); 301113db2ddSJeff Roberson for (i = start; i < end; i++) { 302113db2ddSJeff Roberson if ((map & bit) == 0) 303113db2ddSJeff Roberson break; 304113db2ddSJeff Roberson if ((i & (NBBY - 1)) != (NBBY - 1)) { 305113db2ddSJeff Roberson bit <<= 1; 306113db2ddSJeff Roberson } else { 307113db2ddSJeff Roberson map = *mapp++; 308113db2ddSJeff Roberson bit = 1; 309113db2ddSJeff Roberson } 310113db2ddSJeff Roberson } 311113db2ddSJeff Roberson forw = i - start; 312113db2ddSJeff Roberson /* 313113db2ddSJeff Roberson * Find the size of the cluster going backward. 314113db2ddSJeff Roberson */ 315113db2ddSJeff Roberson start = blkno - 1; 316113db2ddSJeff Roberson end = start - fs->fs_contigsumsize; 317113db2ddSJeff Roberson if (end < 0) 318113db2ddSJeff Roberson end = -1; 319113db2ddSJeff Roberson mapp = &freemapp[start / NBBY]; 320113db2ddSJeff Roberson map = *mapp--; 321113db2ddSJeff Roberson bit = 1 << (start % NBBY); 322113db2ddSJeff Roberson for (i = start; i > end; i--) { 323113db2ddSJeff Roberson if ((map & bit) == 0) 324113db2ddSJeff Roberson break; 325113db2ddSJeff Roberson if ((i & (NBBY - 1)) != 0) { 326113db2ddSJeff Roberson bit >>= 1; 327113db2ddSJeff Roberson } else { 328113db2ddSJeff Roberson map = *mapp--; 329113db2ddSJeff Roberson bit = 1 << (NBBY - 1); 330113db2ddSJeff Roberson } 331113db2ddSJeff Roberson } 332113db2ddSJeff Roberson back = start - i; 333113db2ddSJeff Roberson /* 334113db2ddSJeff Roberson * Account for old cluster and the possibly new forward and 335113db2ddSJeff Roberson * back clusters. 336113db2ddSJeff Roberson */ 337113db2ddSJeff Roberson i = back + forw + 1; 338113db2ddSJeff Roberson if (i > fs->fs_contigsumsize) 339113db2ddSJeff Roberson i = fs->fs_contigsumsize; 340113db2ddSJeff Roberson sump[i] += cnt; 341113db2ddSJeff Roberson if (back > 0) 342113db2ddSJeff Roberson sump[back] -= cnt; 343113db2ddSJeff Roberson if (forw > 0) 344113db2ddSJeff Roberson sump[forw] -= cnt; 345113db2ddSJeff Roberson /* 346113db2ddSJeff Roberson * Update cluster summary information. 347113db2ddSJeff Roberson */ 348113db2ddSJeff Roberson lp = &sump[fs->fs_contigsumsize]; 349113db2ddSJeff Roberson for (i = fs->fs_contigsumsize; i > 0; i--) 350113db2ddSJeff Roberson if (*lp-- > 0) 351113db2ddSJeff Roberson break; 352113db2ddSJeff Roberson fs->fs_maxcluster[cgp->cg_cgx] = i; 353113db2ddSJeff Roberson } 354