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/extattr.h> 39 #include <ufs/ufs/quota.h> 40 #include <ufs/ufs/ufsmount.h> 41 #include <ufs/ufs/dinode.h> 42 #include <ufs/ffs/fs.h> 43 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include <libufs.h> 52 53 ufs2_daddr_t 54 cgballoc(struct uufsd *disk) 55 { 56 u_int8_t *blksfree; 57 struct cg *cgp; 58 struct fs *fs; 59 long bno; 60 61 fs = &disk->d_fs; 62 cgp = &disk->d_cg; 63 blksfree = cg_blksfree(cgp); 64 for (bno = 0; bno < fs->fs_fpg / fs->fs_frag; bno++) 65 if (ffs_isblock(fs, blksfree, bno)) 66 goto gotit; 67 return (0); 68 gotit: 69 fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 70 ffs_clrblock(fs, blksfree, (long)bno); 71 ffs_clusteracct(fs, cgp, bno, -1); 72 cgp->cg_cs.cs_nbfree--; 73 fs->fs_cstotal.cs_nbfree--; 74 fs->fs_fmod = 1; 75 return (cgbase(fs, cgp->cg_cgx) + blkstofrags(fs, bno)); 76 } 77 78 int 79 cgbfree(struct uufsd *disk, ufs2_daddr_t bno, long size) 80 { 81 u_int8_t *blksfree; 82 struct fs *fs; 83 struct cg *cgp; 84 ufs1_daddr_t fragno, cgbno; 85 int i, cg, blk, frags, bbase; 86 87 fs = &disk->d_fs; 88 cg = dtog(fs, bno); 89 if (cgread1(disk, cg) != 1) 90 return (-1); 91 cgp = &disk->d_cg; 92 cgbno = dtogd(fs, bno); 93 blksfree = cg_blksfree(cgp); 94 if (size == fs->fs_bsize) { 95 fragno = fragstoblks(fs, cgbno); 96 ffs_setblock(fs, blksfree, fragno); 97 ffs_clusteracct(fs, cgp, fragno, 1); 98 cgp->cg_cs.cs_nbfree++; 99 fs->fs_cstotal.cs_nbfree++; 100 fs->fs_cs(fs, cg).cs_nbfree++; 101 } else { 102 bbase = cgbno - fragnum(fs, cgbno); 103 /* 104 * decrement the counts associated with the old frags 105 */ 106 blk = blkmap(fs, blksfree, bbase); 107 ffs_fragacct(fs, blk, cgp->cg_frsum, -1); 108 /* 109 * deallocate the fragment 110 */ 111 frags = numfrags(fs, size); 112 for (i = 0; i < frags; i++) 113 setbit(blksfree, cgbno + i); 114 cgp->cg_cs.cs_nffree += i; 115 fs->fs_cstotal.cs_nffree += i; 116 fs->fs_cs(fs, cg).cs_nffree += i; 117 /* 118 * add back in counts associated with the new frags 119 */ 120 blk = blkmap(fs, blksfree, bbase); 121 ffs_fragacct(fs, blk, cgp->cg_frsum, 1); 122 /* 123 * if a complete block has been reassembled, account for it 124 */ 125 fragno = fragstoblks(fs, bbase); 126 if (ffs_isblock(fs, blksfree, fragno)) { 127 cgp->cg_cs.cs_nffree -= fs->fs_frag; 128 fs->fs_cstotal.cs_nffree -= fs->fs_frag; 129 fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 130 ffs_clusteracct(fs, cgp, fragno, 1); 131 cgp->cg_cs.cs_nbfree++; 132 fs->fs_cstotal.cs_nbfree++; 133 fs->fs_cs(fs, cg).cs_nbfree++; 134 } 135 } 136 return cgwrite(disk); 137 } 138 139 ino_t 140 cgialloc(struct uufsd *disk) 141 { 142 struct ufs2_dinode *dp2; 143 u_int8_t *inosused; 144 struct cg *cgp; 145 struct fs *fs; 146 ino_t ino; 147 int i; 148 149 fs = &disk->d_fs; 150 cgp = &disk->d_cg; 151 inosused = cg_inosused(cgp); 152 for (ino = 0; ino < fs->fs_ipg; ino++) 153 if (isclr(inosused, ino)) 154 goto gotit; 155 return (0); 156 gotit: 157 if (fs->fs_magic == FS_UFS2_MAGIC && 158 ino + INOPB(fs) > cgp->cg_initediblk && 159 cgp->cg_initediblk < cgp->cg_niblk) { 160 char block[MAXBSIZE]; 161 bzero(block, (int)fs->fs_bsize); 162 dp2 = (struct ufs2_dinode *)█ 163 for (i = 0; i < INOPB(fs); i++) { 164 dp2->di_gen = arc4random(); 165 dp2++; 166 } 167 if (bwrite(disk, ino_to_fsba(fs, 168 cgp->cg_cgx * fs->fs_ipg + cgp->cg_initediblk), 169 block, fs->fs_bsize)) 170 return (0); 171 cgp->cg_initediblk += INOPB(fs); 172 } 173 174 setbit(inosused, ino); 175 cgp->cg_irotor = ino; 176 cgp->cg_cs.cs_nifree--; 177 fs->fs_cstotal.cs_nifree--; 178 fs->fs_cs(fs, cgp->cg_cgx).cs_nifree--; 179 fs->fs_fmod = 1; 180 181 return (ino + (cgp->cg_cgx * fs->fs_ipg)); 182 } 183 184 int 185 cgread(struct uufsd *disk) 186 { 187 188 if (disk->d_ccg >= disk->d_fs.fs_ncg) 189 return (0); 190 return (cgread1(disk, disk->d_ccg++)); 191 } 192 193 /* Short read/write error messages from cgget()/cgput() */ 194 static const char *failmsg; 195 196 int 197 cgread1(struct uufsd *disk, int c) 198 { 199 200 if (cgget(disk->d_fd, &disk->d_fs, c, &disk->d_cg) == 0) { 201 disk->d_lcg = c; 202 return (1); 203 } 204 ERROR(disk, NULL); 205 if (failmsg != NULL) { 206 ERROR(disk, failmsg); 207 return (-1); 208 } 209 switch (errno) { 210 case EINTEGRITY: 211 ERROR(disk, "cylinder group checks failed"); 212 break; 213 case EIO: 214 ERROR(disk, "read error from block device"); 215 break; 216 default: 217 ERROR(disk, strerror(errno)); 218 break; 219 } 220 return (-1); 221 } 222 223 int 224 cgget(int devfd, struct fs *fs, int cg, struct cg *cgp) 225 { 226 uint32_t cghash, calchash; 227 size_t cnt; 228 229 failmsg = NULL; 230 if ((cnt = pread(devfd, cgp, fs->fs_cgsize, 231 fsbtodb(fs, cgtod(fs, cg)) * (fs->fs_fsize / fsbtodb(fs,1)))) < 0) 232 return (-1); 233 if (cnt == 0) { 234 failmsg = "end of file from block device"; 235 errno = EIO; 236 return (-1); 237 } 238 if (cnt != fs->fs_cgsize) { 239 failmsg = "short read from block device"; 240 errno = EIO; 241 return (-1); 242 } 243 calchash = cgp->cg_ckhash; 244 if ((fs->fs_metackhash & CK_CYLGRP) != 0) { 245 cghash = cgp->cg_ckhash; 246 cgp->cg_ckhash = 0; 247 calchash = calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize); 248 cgp->cg_ckhash = cghash; 249 } 250 if (cgp->cg_ckhash != calchash || !cg_chkmagic(cgp) || 251 cgp->cg_cgx != cg) { 252 errno = EINTEGRITY; 253 return (-1); 254 } 255 return (0); 256 } 257 258 int 259 cgwrite(struct uufsd *disk) 260 { 261 262 return (cgwrite1(disk, disk->d_cg.cg_cgx)); 263 } 264 265 int 266 cgwrite1(struct uufsd *disk, int cg) 267 { 268 static char errmsg[BUFSIZ]; 269 270 if (cg == disk->d_cg.cg_cgx) { 271 if (cgput(disk->d_fd, &disk->d_fs, &disk->d_cg) == 0) 272 return (0); 273 ERROR(disk, NULL); 274 if (failmsg != NULL) { 275 ERROR(disk, failmsg); 276 return (-1); 277 } 278 switch (errno) { 279 case EIO: 280 ERROR(disk, "unable to write cylinder group"); 281 break; 282 default: 283 ERROR(disk, strerror(errno)); 284 break; 285 } 286 return (-1); 287 } 288 snprintf(errmsg, BUFSIZ, "Cylinder group %d in buffer does not match " 289 "the cylinder group %d that cgwrite1 requested", 290 disk->d_cg.cg_cgx, cg); 291 ERROR(disk, errmsg); 292 errno = EDOOFUS; 293 return (-1); 294 } 295 296 int 297 cgput(int devfd, struct fs *fs, struct cg *cgp) 298 { 299 size_t cnt; 300 301 if ((fs->fs_metackhash & CK_CYLGRP) != 0) { 302 cgp->cg_ckhash = 0; 303 cgp->cg_ckhash = 304 calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize); 305 } 306 failmsg = NULL; 307 if ((cnt = pwrite(devfd, cgp, fs->fs_cgsize, 308 fsbtodb(fs, cgtod(fs, cgp->cg_cgx)) * 309 (fs->fs_fsize / fsbtodb(fs,1)))) < 0) 310 return (-1); 311 if (cnt != fs->fs_cgsize) { 312 failmsg = "short write to block device"; 313 return (-1); 314 } 315 return (0); 316 } 317