1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2003 Juli Mallett. All rights reserved. 5 * 6 * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the 7 * FreeBSD project. Redistribution and use in source and binary forms, with 8 * or without modification, are permitted provided that the following 9 * conditions are met: 10 * 11 * 1. Redistribution of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 2. Redistribution 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 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/mount.h> 35 #include <sys/disklabel.h> 36 #include <sys/stat.h> 37 38 #include <ufs/ufs/ufsmount.h> 39 #include <ufs/ufs/dinode.h> 40 #include <ufs/ffs/fs.h> 41 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include <libufs.h> 50 51 ufs2_daddr_t 52 cgballoc(struct uufsd *disk) 53 { 54 u_int8_t *blksfree; 55 struct cg *cgp; 56 struct fs *fs; 57 long bno; 58 59 fs = &disk->d_fs; 60 cgp = &disk->d_cg; 61 blksfree = cg_blksfree(cgp); 62 for (bno = 0; bno < fs->fs_fpg / fs->fs_frag; bno++) 63 if (ffs_isblock(fs, blksfree, bno)) 64 goto gotit; 65 return (0); 66 gotit: 67 fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 68 ffs_clrblock(fs, blksfree, (long)bno); 69 ffs_clusteracct(fs, cgp, bno, -1); 70 cgp->cg_cs.cs_nbfree--; 71 fs->fs_cstotal.cs_nbfree--; 72 fs->fs_fmod = 1; 73 return (cgbase(fs, cgp->cg_cgx) + blkstofrags(fs, bno)); 74 } 75 76 int 77 cgbfree(struct uufsd *disk, ufs2_daddr_t bno, long size) 78 { 79 u_int8_t *blksfree; 80 struct fs *fs; 81 struct cg *cgp; 82 ufs1_daddr_t fragno, cgbno; 83 int i, cg, blk, frags, bbase; 84 85 fs = &disk->d_fs; 86 cg = dtog(fs, bno); 87 if (cgread1(disk, cg) != 1) 88 return (-1); 89 cgp = &disk->d_cg; 90 cgbno = dtogd(fs, bno); 91 blksfree = cg_blksfree(cgp); 92 if (size == fs->fs_bsize) { 93 fragno = fragstoblks(fs, cgbno); 94 ffs_setblock(fs, blksfree, fragno); 95 ffs_clusteracct(fs, cgp, fragno, 1); 96 cgp->cg_cs.cs_nbfree++; 97 fs->fs_cstotal.cs_nbfree++; 98 fs->fs_cs(fs, cg).cs_nbfree++; 99 } else { 100 bbase = cgbno - fragnum(fs, cgbno); 101 /* 102 * decrement the counts associated with the old frags 103 */ 104 blk = blkmap(fs, blksfree, bbase); 105 ffs_fragacct(fs, blk, cgp->cg_frsum, -1); 106 /* 107 * deallocate the fragment 108 */ 109 frags = numfrags(fs, size); 110 for (i = 0; i < frags; i++) 111 setbit(blksfree, cgbno + i); 112 cgp->cg_cs.cs_nffree += i; 113 fs->fs_cstotal.cs_nffree += i; 114 fs->fs_cs(fs, cg).cs_nffree += i; 115 /* 116 * add back in counts associated with the new frags 117 */ 118 blk = blkmap(fs, blksfree, bbase); 119 ffs_fragacct(fs, blk, cgp->cg_frsum, 1); 120 /* 121 * if a complete block has been reassembled, account for it 122 */ 123 fragno = fragstoblks(fs, bbase); 124 if (ffs_isblock(fs, blksfree, fragno)) { 125 cgp->cg_cs.cs_nffree -= fs->fs_frag; 126 fs->fs_cstotal.cs_nffree -= fs->fs_frag; 127 fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 128 ffs_clusteracct(fs, cgp, fragno, 1); 129 cgp->cg_cs.cs_nbfree++; 130 fs->fs_cstotal.cs_nbfree++; 131 fs->fs_cs(fs, cg).cs_nbfree++; 132 } 133 } 134 return cgwrite(disk); 135 } 136 137 ino_t 138 cgialloc(struct uufsd *disk) 139 { 140 struct ufs2_dinode *dp2; 141 u_int8_t *inosused; 142 struct cg *cgp; 143 struct fs *fs; 144 ino_t ino; 145 int i; 146 147 fs = &disk->d_fs; 148 cgp = &disk->d_cg; 149 inosused = cg_inosused(cgp); 150 for (ino = 0; ino < fs->fs_ipg; ino++) 151 if (isclr(inosused, ino)) 152 goto gotit; 153 return (0); 154 gotit: 155 if (fs->fs_magic == FS_UFS2_MAGIC && 156 ino + INOPB(fs) > cgp->cg_initediblk && 157 cgp->cg_initediblk < cgp->cg_niblk) { 158 char block[MAXBSIZE]; 159 bzero(block, (int)fs->fs_bsize); 160 dp2 = (struct ufs2_dinode *)█ 161 for (i = 0; i < INOPB(fs); i++) { 162 dp2->di_gen = arc4random(); 163 dp2++; 164 } 165 if (bwrite(disk, ino_to_fsba(fs, 166 cgp->cg_cgx * fs->fs_ipg + cgp->cg_initediblk), 167 block, fs->fs_bsize)) 168 return (0); 169 cgp->cg_initediblk += INOPB(fs); 170 } 171 172 setbit(inosused, ino); 173 cgp->cg_irotor = ino; 174 cgp->cg_cs.cs_nifree--; 175 fs->fs_cstotal.cs_nifree--; 176 fs->fs_cs(fs, cgp->cg_cgx).cs_nifree--; 177 fs->fs_fmod = 1; 178 179 return (ino + (cgp->cg_cgx * fs->fs_ipg)); 180 } 181 182 int 183 cgread(struct uufsd *disk) 184 { 185 186 if (disk->d_ccg >= disk->d_fs.fs_ncg) 187 return (0); 188 return (cgread1(disk, disk->d_ccg++)); 189 } 190 191 /* Short read/write error messages from cgget()/cgput() */ 192 static const char *failmsg; 193 194 int 195 cgread1(struct uufsd *disk, int c) 196 { 197 198 if (cgget(disk->d_fd, &disk->d_fs, c, &disk->d_cg) == 0) { 199 disk->d_lcg = c; 200 return (1); 201 } 202 ERROR(disk, NULL); 203 if (failmsg != NULL) { 204 ERROR(disk, failmsg); 205 return (-1); 206 } 207 switch (errno) { 208 case EINTEGRITY: 209 ERROR(disk, "cylinder group checks failed"); 210 break; 211 case EIO: 212 ERROR(disk, "read error from block device"); 213 break; 214 default: 215 ERROR(disk, strerror(errno)); 216 break; 217 } 218 return (-1); 219 } 220 221 int 222 cgget(int devfd, struct fs *fs, int cg, struct cg *cgp) 223 { 224 uint32_t cghash, calchash; 225 size_t cnt; 226 227 failmsg = NULL; 228 if ((cnt = pread(devfd, cgp, fs->fs_cgsize, 229 fsbtodb(fs, cgtod(fs, cg)) * (fs->fs_fsize / fsbtodb(fs,1)))) < 0) 230 return (-1); 231 if (cnt == 0) { 232 failmsg = "end of file from block device"; 233 errno = EIO; 234 return (-1); 235 } 236 if (cnt != fs->fs_cgsize) { 237 failmsg = "short read from block device"; 238 errno = EIO; 239 return (-1); 240 } 241 calchash = cgp->cg_ckhash; 242 if ((fs->fs_metackhash & CK_CYLGRP) != 0) { 243 cghash = cgp->cg_ckhash; 244 cgp->cg_ckhash = 0; 245 calchash = calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize); 246 cgp->cg_ckhash = cghash; 247 } 248 if (cgp->cg_ckhash != calchash || !cg_chkmagic(cgp) || 249 cgp->cg_cgx != cg) { 250 errno = EINTEGRITY; 251 return (-1); 252 } 253 return (0); 254 } 255 256 int 257 cgwrite(struct uufsd *disk) 258 { 259 260 return (cgwrite1(disk, disk->d_cg.cg_cgx)); 261 } 262 263 int 264 cgwrite1(struct uufsd *disk, int cg) 265 { 266 static char errmsg[BUFSIZ]; 267 268 if (cg == disk->d_cg.cg_cgx) { 269 if (cgput(disk->d_fd, &disk->d_fs, &disk->d_cg) == 0) 270 return (0); 271 ERROR(disk, NULL); 272 if (failmsg != NULL) { 273 ERROR(disk, failmsg); 274 return (-1); 275 } 276 switch (errno) { 277 case EIO: 278 ERROR(disk, "unable to write cylinder group"); 279 break; 280 default: 281 ERROR(disk, strerror(errno)); 282 break; 283 } 284 return (-1); 285 } 286 snprintf(errmsg, BUFSIZ, "Cylinder group %d in buffer does not match " 287 "the cylinder group %d that cgwrite1 requested", 288 disk->d_cg.cg_cgx, cg); 289 ERROR(disk, errmsg); 290 errno = EDOOFUS; 291 return (-1); 292 } 293 294 int 295 cgput(int devfd, struct fs *fs, struct cg *cgp) 296 { 297 size_t cnt; 298 299 if ((fs->fs_metackhash & CK_CYLGRP) != 0) { 300 cgp->cg_ckhash = 0; 301 cgp->cg_ckhash = 302 calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize); 303 } 304 failmsg = NULL; 305 if ((cnt = pwrite(devfd, cgp, fs->fs_cgsize, 306 fsbtodb(fs, cgtod(fs, cgp->cg_cgx)) * 307 (fs->fs_fsize / fsbtodb(fs,1)))) < 0) 308 return (-1); 309 if (cnt != fs->fs_cgsize) { 310 failmsg = "short write to block device"; 311 return (-1); 312 } 313 return (0); 314 } 315