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