1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1982, 1986, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/param.h> 38 39 #ifndef _KERNEL 40 #include <ufs/ufs/dinode.h> 41 #include <ufs/ffs/fs.h> 42 #else 43 #include <sys/systm.h> 44 #include <sys/lock.h> 45 #include <sys/malloc.h> 46 #include <sys/mount.h> 47 #include <sys/vnode.h> 48 #include <sys/bio.h> 49 #include <sys/buf.h> 50 #include <sys/ucred.h> 51 52 #include <ufs/ufs/quota.h> 53 #include <ufs/ufs/inode.h> 54 #include <ufs/ufs/extattr.h> 55 #include <ufs/ufs/ufsmount.h> 56 #include <ufs/ufs/ufs_extern.h> 57 #include <ufs/ffs/ffs_extern.h> 58 #include <ufs/ffs/fs.h> 59 60 /* 61 * Return buffer with the contents of block "offset" from the beginning of 62 * directory "ip". If "res" is non-zero, fill it in with a pointer to the 63 * remaining space in the directory. 64 */ 65 int 66 ffs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp) 67 { 68 struct inode *ip; 69 struct fs *fs; 70 struct buf *bp; 71 ufs_lbn_t lbn; 72 int bsize, error; 73 74 ip = VTOI(vp); 75 fs = ITOFS(ip); 76 lbn = lblkno(fs, offset); 77 bsize = blksize(fs, ip, lbn); 78 79 *bpp = NULL; 80 error = bread(vp, lbn, bsize, NOCRED, &bp); 81 if (error) { 82 brelse(bp); 83 return (error); 84 } 85 if (res) 86 *res = (char *)bp->b_data + blkoff(fs, offset); 87 *bpp = bp; 88 return (0); 89 } 90 91 /* 92 * Load up the contents of an inode and copy the appropriate pieces 93 * to the incore copy. 94 */ 95 void 96 ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino) 97 { 98 99 if (I_IS_UFS1(ip)) { 100 *ip->i_din1 = 101 *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 102 ip->i_mode = ip->i_din1->di_mode; 103 ip->i_nlink = ip->i_din1->di_nlink; 104 ip->i_size = ip->i_din1->di_size; 105 ip->i_flags = ip->i_din1->di_flags; 106 ip->i_gen = ip->i_din1->di_gen; 107 ip->i_uid = ip->i_din1->di_uid; 108 ip->i_gid = ip->i_din1->di_gid; 109 } else { 110 *ip->i_din2 = 111 *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 112 ip->i_mode = ip->i_din2->di_mode; 113 ip->i_nlink = ip->i_din2->di_nlink; 114 ip->i_size = ip->i_din2->di_size; 115 ip->i_flags = ip->i_din2->di_flags; 116 ip->i_gen = ip->i_din2->di_gen; 117 ip->i_uid = ip->i_din2->di_uid; 118 ip->i_gid = ip->i_din2->di_gid; 119 } 120 } 121 #endif /* KERNEL */ 122 123 /* 124 * Update the frsum fields to reflect addition or deletion 125 * of some frags. 126 */ 127 void 128 ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt) 129 { 130 int inblk; 131 int field, subfield; 132 int siz, pos; 133 134 inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 135 fragmap <<= 1; 136 for (siz = 1; siz < fs->fs_frag; siz++) { 137 if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 138 continue; 139 field = around[siz]; 140 subfield = inside[siz]; 141 for (pos = siz; pos <= fs->fs_frag; pos++) { 142 if ((fragmap & field) == subfield) { 143 fraglist[siz] += cnt; 144 pos += siz; 145 field <<= siz; 146 subfield <<= siz; 147 } 148 field <<= 1; 149 subfield <<= 1; 150 } 151 } 152 } 153 154 /* 155 * block operations 156 * 157 * check if a block is available 158 */ 159 int 160 ffs_isblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h) 161 { 162 unsigned char mask; 163 164 switch ((int)fs->fs_frag) { 165 case 8: 166 return (cp[h] == 0xff); 167 case 4: 168 mask = 0x0f << ((h & 0x1) << 2); 169 return ((cp[h >> 1] & mask) == mask); 170 case 2: 171 mask = 0x03 << ((h & 0x3) << 1); 172 return ((cp[h >> 2] & mask) == mask); 173 case 1: 174 mask = 0x01 << (h & 0x7); 175 return ((cp[h >> 3] & mask) == mask); 176 default: 177 #ifdef _KERNEL 178 panic("ffs_isblock"); 179 #endif 180 break; 181 } 182 return (0); 183 } 184 185 /* 186 * check if a block is free 187 */ 188 int 189 ffs_isfreeblock(struct fs *fs, u_char *cp, ufs1_daddr_t h) 190 { 191 192 switch ((int)fs->fs_frag) { 193 case 8: 194 return (cp[h] == 0); 195 case 4: 196 return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); 197 case 2: 198 return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); 199 case 1: 200 return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); 201 default: 202 #ifdef _KERNEL 203 panic("ffs_isfreeblock"); 204 #endif 205 break; 206 } 207 return (0); 208 } 209 210 /* 211 * take a block out of the map 212 */ 213 void 214 ffs_clrblock(struct fs *fs, u_char *cp, ufs1_daddr_t h) 215 { 216 217 switch ((int)fs->fs_frag) { 218 case 8: 219 cp[h] = 0; 220 return; 221 case 4: 222 cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 223 return; 224 case 2: 225 cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 226 return; 227 case 1: 228 cp[h >> 3] &= ~(0x01 << (h & 0x7)); 229 return; 230 default: 231 #ifdef _KERNEL 232 panic("ffs_clrblock"); 233 #endif 234 break; 235 } 236 } 237 238 /* 239 * put a block into the map 240 */ 241 void 242 ffs_setblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h) 243 { 244 245 switch ((int)fs->fs_frag) { 246 247 case 8: 248 cp[h] = 0xff; 249 return; 250 case 4: 251 cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 252 return; 253 case 2: 254 cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 255 return; 256 case 1: 257 cp[h >> 3] |= (0x01 << (h & 0x7)); 258 return; 259 default: 260 #ifdef _KERNEL 261 panic("ffs_setblock"); 262 #endif 263 break; 264 } 265 } 266 267 /* 268 * Update the cluster map because of an allocation or free. 269 * 270 * Cnt == 1 means free; cnt == -1 means allocating. 271 */ 272 void 273 ffs_clusteracct(struct fs *fs, struct cg *cgp, ufs1_daddr_t blkno, int cnt) 274 { 275 int32_t *sump; 276 int32_t *lp; 277 u_char *freemapp, *mapp; 278 int i, start, end, forw, back, map, bit; 279 280 if (fs->fs_contigsumsize <= 0) 281 return; 282 freemapp = cg_clustersfree(cgp); 283 sump = cg_clustersum(cgp); 284 /* 285 * Allocate or clear the actual block. 286 */ 287 if (cnt > 0) 288 setbit(freemapp, blkno); 289 else 290 clrbit(freemapp, blkno); 291 /* 292 * Find the size of the cluster going forward. 293 */ 294 start = blkno + 1; 295 end = start + fs->fs_contigsumsize; 296 if (end >= cgp->cg_nclusterblks) 297 end = cgp->cg_nclusterblks; 298 mapp = &freemapp[start / NBBY]; 299 map = *mapp++; 300 bit = 1 << (start % NBBY); 301 for (i = start; i < end; i++) { 302 if ((map & bit) == 0) 303 break; 304 if ((i & (NBBY - 1)) != (NBBY - 1)) { 305 bit <<= 1; 306 } else { 307 map = *mapp++; 308 bit = 1; 309 } 310 } 311 forw = i - start; 312 /* 313 * Find the size of the cluster going backward. 314 */ 315 start = blkno - 1; 316 end = start - fs->fs_contigsumsize; 317 if (end < 0) 318 end = -1; 319 mapp = &freemapp[start / NBBY]; 320 map = *mapp--; 321 bit = 1 << (start % NBBY); 322 for (i = start; i > end; i--) { 323 if ((map & bit) == 0) 324 break; 325 if ((i & (NBBY - 1)) != 0) { 326 bit >>= 1; 327 } else { 328 map = *mapp--; 329 bit = 1 << (NBBY - 1); 330 } 331 } 332 back = start - i; 333 /* 334 * Account for old cluster and the possibly new forward and 335 * back clusters. 336 */ 337 i = back + forw + 1; 338 if (i > fs->fs_contigsumsize) 339 i = fs->fs_contigsumsize; 340 sump[i] += cnt; 341 if (back > 0) 342 sump[back] -= cnt; 343 if (forw > 0) 344 sump[forw] -= cnt; 345 /* 346 * Update cluster summary information. 347 */ 348 lp = &sump[fs->fs_contigsumsize]; 349 for (i = fs->fs_contigsumsize; i > 0; i--) 350 if (*lp-- > 0) 351 break; 352 fs->fs_maxcluster[cgp->cg_cgx] = i; 353 } 354