1 /* $OpenBSD: ffs_subr.c,v 1.34 2021/10/20 06:35:39 semarie Exp $ */ 2 /* $NetBSD: ffs_subr.c,v 1.6 1996/03/17 02:16:23 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)ffs_subr.c 8.2 (Berkeley) 9/21/93 33 */ 34 35 #include <sys/param.h> 36 #include <ufs/ffs/fs.h> 37 38 #ifdef _KERNEL 39 #include <sys/systm.h> 40 #include <sys/vnode.h> 41 #include <sys/mount.h> 42 #include <sys/buf.h> 43 44 #include <ufs/ufs/quota.h> 45 #include <ufs/ufs/inode.h> 46 #include <ufs/ufs/ufsmount.h> 47 #include <ufs/ufs/ufs_extern.h> 48 49 #include <ufs/ffs/ffs_extern.h> 50 51 /* 52 * Return buffer with the contents of block "offset" from the beginning of 53 * directory "ip". If "res" is non-zero, fill it in with a pointer to the 54 * remaining space in the directory. 55 */ 56 int 57 ffs_bufatoff(struct inode *ip, off_t offset, char **res, struct buf **bpp) 58 { 59 struct fs *fs; 60 struct vnode *vp; 61 struct buf *bp; 62 daddr_t lbn; 63 int bsize, error; 64 65 vp = ITOV(ip); 66 fs = ip->i_fs; 67 lbn = lblkno(fs, offset); 68 bsize = blksize(fs, ip, lbn); 69 70 *bpp = NULL; 71 if ((error = bread(vp, lbn, fs->fs_bsize, &bp)) != 0) { 72 brelse(bp); 73 return (error); 74 } 75 buf_adjcnt(bp, bsize); 76 if (res) 77 *res = (char *)bp->b_data + blkoff(fs, offset); 78 *bpp = bp; 79 return (0); 80 } 81 #else 82 /* Prototypes for userland */ 83 void ffs_fragacct(struct fs *, int, int32_t[], int); 84 int ffs_isfreeblock(struct fs *, u_char *, daddr_t); 85 int ffs_isblock(struct fs *, u_char *, daddr_t); 86 void ffs_clrblock(struct fs *, u_char *, daddr_t); 87 void ffs_setblock(struct fs *, u_char *, daddr_t); 88 __dead void panic(const char *, ...); 89 #endif 90 91 /* 92 * Update the frsum fields to reflect addition or deletion 93 * of some frags. 94 */ 95 void 96 ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt) 97 { 98 int inblk; 99 int field, subfield; 100 int siz, pos; 101 102 inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; 103 fragmap <<= 1; 104 for (siz = 1; siz < fs->fs_frag; siz++) { 105 if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) 106 continue; 107 field = around[siz]; 108 subfield = inside[siz]; 109 for (pos = siz; pos <= fs->fs_frag; pos++) { 110 if ((fragmap & field) == subfield) { 111 fraglist[siz] += cnt; 112 pos += siz; 113 field <<= siz; 114 subfield <<= siz; 115 } 116 field <<= 1; 117 subfield <<= 1; 118 } 119 } 120 } 121 122 #if defined(_KERNEL) && defined(DIAGNOSTIC) 123 void 124 ffs_checkoverlap(struct buf *bp, struct inode *ip) 125 { 126 daddr_t start, last; 127 struct vnode *vp; 128 struct buf *ep; 129 130 start = bp->b_blkno; 131 last = start + btodb(bp->b_bcount) - 1; 132 LIST_FOREACH(ep, &bufhead, b_list) { 133 if (ep == bp || (ep->b_flags & B_INVAL) || 134 ep->b_vp == NULLVP) 135 continue; 136 if (VOP_BMAP(ep->b_vp, 0, &vp, NULL, NULL)) 137 continue; 138 if (vp != ip->i_devvp) 139 continue; 140 /* look for overlap */ 141 if (ep->b_bcount == 0 || ep->b_blkno > last || 142 ep->b_blkno + btodb(ep->b_bcount) <= start) 143 continue; 144 vprint("Disk overlap", vp); 145 (void)printf("\tstart %lld, end %lld overlap start %llu, " 146 "end %llu\n", (long long)start, (long long)last, 147 (long long)ep->b_blkno, 148 (long long)(ep->b_blkno + btodb(ep->b_bcount) - 1)); 149 panic("Disk buffer overlap"); 150 } 151 } 152 #endif /* DIAGNOSTIC */ 153 154 /* 155 * block operations 156 * 157 * check if a block is available 158 */ 159 int 160 ffs_isblock(struct fs *fs, u_char *cp, daddr_t h) 161 { 162 u_char mask; 163 164 switch (fs->fs_frag) { 165 default: 166 case 8: 167 return (cp[h] == 0xff); 168 case 4: 169 mask = 0x0f << ((h & 0x1) << 2); 170 return ((cp[h >> 1] & mask) == mask); 171 case 2: 172 mask = 0x03 << ((h & 0x3) << 1); 173 return ((cp[h >> 2] & mask) == mask); 174 case 1: 175 mask = 0x01 << (h & 0x7); 176 return ((cp[h >> 3] & mask) == mask); 177 } 178 } 179 180 /* 181 * take a block out of the map 182 */ 183 void 184 ffs_clrblock(struct fs *fs, u_char *cp, daddr_t h) 185 { 186 187 switch (fs->fs_frag) { 188 default: 189 case 8: 190 cp[h] = 0; 191 return; 192 case 4: 193 cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 194 return; 195 case 2: 196 cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 197 return; 198 case 1: 199 cp[h >> 3] &= ~(0x01 << (h & 0x7)); 200 return; 201 } 202 } 203 204 /* 205 * put a block into the map 206 */ 207 void 208 ffs_setblock(struct fs *fs, u_char *cp, daddr_t h) 209 { 210 211 switch (fs->fs_frag) { 212 default: 213 case 8: 214 cp[h] = 0xff; 215 return; 216 case 4: 217 cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 218 return; 219 case 2: 220 cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 221 return; 222 case 1: 223 cp[h >> 3] |= (0x01 << (h & 0x7)); 224 return; 225 } 226 } 227 228 /* 229 * check if a block is free 230 */ 231 int 232 ffs_isfreeblock(struct fs *fs, u_char *cp, daddr_t h) 233 { 234 235 switch (fs->fs_frag) { 236 default: 237 case 8: 238 return (cp[h] == 0); 239 case 4: 240 return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); 241 case 2: 242 return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); 243 case 1: 244 return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); 245 } 246 } 247 248 #ifdef _KERNEL 249 /* 250 * Initialize the vnode associated with a new inode, handle aliased 251 * vnodes. 252 */ 253 int 254 ffs_vinit(struct mount *mntp, struct vnode **vpp) 255 { 256 struct inode *ip; 257 struct vnode *vp, *nvp; 258 struct timeval mtv; 259 260 vp = *vpp; 261 ip = VTOI(vp); 262 switch(vp->v_type = IFTOVT(DIP(ip, mode))) { 263 case VCHR: 264 case VBLK: 265 vp->v_op = &ffs_specvops; 266 if ((nvp = checkalias(vp, DIP(ip, rdev), mntp)) != NULL) { 267 /* 268 * Discard unneeded vnode, but save its inode. 269 * Note that the lock is carried over in the inode 270 * to the replacement vnode. 271 */ 272 nvp->v_data = vp->v_data; 273 vp->v_data = NULL; 274 vp->v_op = &spec_vops; 275 #ifdef VFSLCKDEBUG 276 vp->v_flag &= ~VLOCKSWORK; 277 #endif 278 vrele(vp); 279 vgone(vp); 280 /* 281 * Reinitialize aliased inode. 282 */ 283 vp = nvp; 284 ip->i_vnode = vp; 285 } 286 break; 287 case VFIFO: 288 #ifdef FIFO 289 vp->v_op = &ffs_fifovops; 290 break; 291 #else 292 return (EOPNOTSUPP); 293 #endif 294 case VNON: 295 case VBAD: 296 case VSOCK: 297 case VLNK: 298 case VDIR: 299 case VREG: 300 break; 301 } 302 if (ip->i_number == ROOTINO) 303 vp->v_flag |= VROOT; 304 /* 305 * Initialize modrev times 306 */ 307 getmicrouptime(&mtv); 308 ip->i_modrev = (u_quad_t)mtv.tv_sec << 32; 309 ip->i_modrev |= (u_quad_t)mtv.tv_usec * 4294; 310 *vpp = vp; 311 return (0); 312 } 313 #endif /* _KERNEL */ 314