155714Skris/*- 255714Skris * SPDX-License-Identifier: BSD-2-Clause 355714Skris * 455714Skris * Copyright (c) 2003 Juli Mallett. All rights reserved. 555714Skris * 655714Skris * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the 755714Skris * FreeBSD project. Redistribution and use in source and binary forms, with 8280304Sjkim * or without modification, are permitted provided that the following 955714Skris * conditions are met: 1055714Skris * 1155714Skris * 1. Redistribution of source code must retain the above copyright notice, 1255714Skris * this list of conditions and the following disclaimer. 1355714Skris * 2. Redistribution in binary form must reproduce the above copyright 1455714Skris * notice, this list of conditions and the following disclaimer in the 15280304Sjkim * documentation and/or other materials provided with the distribution. 1655714Skris * 1755714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1855714Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1955714Skris * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2055714Skris * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2155714Skris * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22280304Sjkim * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2355714Skris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2455714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2555714Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 2655714Skris * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2755714Skris * POSSIBILITY OF SUCH DAMAGE. 2855714Skris */ 2955714Skris 3055714Skris#include <sys/param.h> 3155714Skris#include <sys/mount.h> 3255714Skris#include <sys/disklabel.h> 3355714Skris#include <sys/stat.h> 3455714Skris 3555714Skris#include <ufs/ufs/extattr.h> 3655714Skris#include <ufs/ufs/quota.h> 37280304Sjkim#include <ufs/ufs/ufsmount.h> 3855714Skris#include <ufs/ufs/dinode.h> 3955714Skris#include <ufs/ffs/fs.h> 40280304Sjkim 4155714Skris#include <errno.h> 4255714Skris#include <fcntl.h> 4355714Skris#include <stdio.h> 4455714Skris#include <stdlib.h> 4555714Skris#include <string.h> 4655714Skris#include <unistd.h> 4755714Skris 4855714Skris#include <libufs.h> 4955714Skris 5055714Skrisufs2_daddr_t 5155714Skriscgballoc(struct uufsd *disk) 52280304Sjkim{ 5355714Skris u_int8_t *blksfree; 5455714Skris struct cg *cgp; 5555714Skris struct fs *fs; 5655714Skris long bno; 5755714Skris 5855714Skris fs = &disk->d_fs; 5955714Skris cgp = &disk->d_cg; 6055714Skris blksfree = cg_blksfree(cgp); 6155714Skris for (bno = 0; bno < fs->fs_fpg / fs->fs_frag; bno++) 6255714Skris if (ffs_isblock(fs, blksfree, bno)) 63280304Sjkim goto gotit; 64280304Sjkim return (0); 65280304Sjkimgotit: 66280304Sjkim fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 67280304Sjkim ffs_clrblock(fs, blksfree, (long)bno); 68280304Sjkim ffs_clusteracct(fs, cgp, bno, -1); 69280304Sjkim cgp->cg_cs.cs_nbfree--; 70280304Sjkim fs->fs_cstotal.cs_nbfree--; 71280304Sjkim fs->fs_fmod = 1; 72280304Sjkim return (cgbase(fs, cgp->cg_cgx) + blkstofrags(fs, bno)); 73280304Sjkim} 74280304Sjkim 75280304Sjkimint 76280304Sjkimcgbfree(struct uufsd *disk, ufs2_daddr_t bno, long size) 77280304Sjkim{ 78280304Sjkim u_int8_t *blksfree; 79280304Sjkim struct fs *fs; 80280304Sjkim struct cg *cgp; 81280304Sjkim ufs1_daddr_t fragno, cgbno; 82280304Sjkim int i, cg, blk, frags, bbase; 83280304Sjkim 84280304Sjkim fs = &disk->d_fs; 85280304Sjkim cg = dtog(fs, bno); 86280304Sjkim if (cgread1(disk, cg) != 1) 87280304Sjkim return (-1); 88280304Sjkim cgp = &disk->d_cg; 89280304Sjkim cgbno = dtogd(fs, bno); 90280304Sjkim blksfree = cg_blksfree(cgp); 91280304Sjkim if (size == fs->fs_bsize) { 92280304Sjkim fragno = fragstoblks(fs, cgbno); 93280304Sjkim ffs_setblock(fs, blksfree, fragno); 94280304Sjkim ffs_clusteracct(fs, cgp, fragno, 1); 95280304Sjkim cgp->cg_cs.cs_nbfree++; 96280304Sjkim fs->fs_cstotal.cs_nbfree++; 97280304Sjkim fs->fs_cs(fs, cg).cs_nbfree++; 98280304Sjkim } else { 9955714Skris bbase = cgbno - fragnum(fs, cgbno); 100109998Smarkm /* 101280304Sjkim * decrement the counts associated with the old frags 102280304Sjkim */ 103280304Sjkim blk = blkmap(fs, blksfree, bbase); 104280304Sjkim ffs_fragacct(fs, blk, cgp->cg_frsum, -1); 105280304Sjkim /* 106280304Sjkim * deallocate the fragment 107280304Sjkim */ 10855714Skris frags = numfrags(fs, size); 109280304Sjkim for (i = 0; i < frags; i++) 110280304Sjkim setbit(blksfree, cgbno + i); 111280304Sjkim cgp->cg_cs.cs_nffree += i; 112280304Sjkim fs->fs_cstotal.cs_nffree += i; 113280304Sjkim fs->fs_cs(fs, cg).cs_nffree += i; 114280304Sjkim /* 115280304Sjkim * add back in counts associated with the new frags 11655714Skris */ 117280304Sjkim blk = blkmap(fs, blksfree, bbase); 118280304Sjkim ffs_fragacct(fs, blk, cgp->cg_frsum, 1); 119280304Sjkim /* 120280304Sjkim * if a complete block has been reassembled, account for it 121280304Sjkim */ 122280304Sjkim fragno = fragstoblks(fs, bbase); 123280304Sjkim if (ffs_isblock(fs, blksfree, fragno)) { 124280304Sjkim cgp->cg_cs.cs_nffree -= fs->fs_frag; 125194206Ssimon fs->fs_cstotal.cs_nffree -= fs->fs_frag; 12655714Skris fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 127109998Smarkm ffs_clusteracct(fs, cgp, fragno, 1); 128280304Sjkim cgp->cg_cs.cs_nbfree++; 129280304Sjkim fs->fs_cstotal.cs_nbfree++; 130280304Sjkim fs->fs_cs(fs, cg).cs_nbfree++; 131280304Sjkim } 132280304Sjkim } 133280304Sjkim return cgwrite(disk); 134280304Sjkim} 135280304Sjkim 136280304Sjkimino_t 137280304Sjkimcgialloc(struct uufsd *disk) 138280304Sjkim{ 13955714Skris struct ufs2_dinode *dp2; 140280304Sjkim u_int8_t *inosused; 141280304Sjkim struct cg *cgp; 142280304Sjkim struct fs *fs; 143280304Sjkim ino_t ino; 144280304Sjkim int i; 145280304Sjkim 14655714Skris fs = &disk->d_fs; 147280304Sjkim cgp = &disk->d_cg; 14855714Skris inosused = cg_inosused(cgp); 149280304Sjkim for (ino = 0; ino < fs->fs_ipg; ino++) 150280304Sjkim if (isclr(inosused, ino)) 151280304Sjkim goto gotit; 152280304Sjkim return (0); 153280304Sjkimgotit: 154280304Sjkim if (fs->fs_magic == FS_UFS2_MAGIC && 155280304Sjkim ino + INOPB(fs) > cgp->cg_initediblk && 156280304Sjkim cgp->cg_initediblk < cgp->cg_niblk) { 157280304Sjkim char block[MAXBSIZE]; 158280304Sjkim bzero(block, (int)fs->fs_bsize); 159280304Sjkim dp2 = (struct ufs2_dinode *)█ 160280304Sjkim for (i = 0; i < INOPB(fs); i++) { 161280304Sjkim dp2->di_gen = arc4random(); 162280304Sjkim dp2++; 163280304Sjkim } 164280304Sjkim if (bwrite(disk, ino_to_fsba(fs, 165280304Sjkim cgp->cg_cgx * fs->fs_ipg + cgp->cg_initediblk), 166280304Sjkim block, fs->fs_bsize)) 167280304Sjkim return (0); 168280304Sjkim cgp->cg_initediblk += INOPB(fs); 169280304Sjkim } 170280304Sjkim 171280304Sjkim setbit(inosused, ino); 172280304Sjkim cgp->cg_irotor = ino; 173280304Sjkim cgp->cg_cs.cs_nifree--; 174280304Sjkim fs->fs_cstotal.cs_nifree--; 175280304Sjkim fs->fs_cs(fs, cgp->cg_cgx).cs_nifree--; 176280304Sjkim fs->fs_fmod = 1; 177280304Sjkim 178280304Sjkim return (ino + (cgp->cg_cgx * fs->fs_ipg)); 179280304Sjkim} 180280304Sjkim 181280304Sjkimint 182280304Sjkimcgread(struct uufsd *disk) 183280304Sjkim{ 184280304Sjkim 185280304Sjkim if (disk->d_ccg >= disk->d_fs.fs_ncg) 186280304Sjkim return (0); 187280304Sjkim return (cgread1(disk, disk->d_ccg++)); 188280304Sjkim} 189280304Sjkim 190280304Sjkim/* Short read/write error messages from cgget()/cgput() */ 191280304Sjkimstatic const char *failmsg; 192280304Sjkim 193280304Sjkimint 194280304Sjkimcgread1(struct uufsd *disk, int c) 195280304Sjkim{ 196280304Sjkim 197280304Sjkim if (cgget(disk->d_fd, &disk->d_fs, c, &disk->d_cg) == 0) { 198280304Sjkim disk->d_lcg = c; 199280304Sjkim return (1); 200280304Sjkim } 201280304Sjkim ERROR(disk, NULL); 202280304Sjkim if (failmsg != NULL) { 203280304Sjkim ERROR(disk, failmsg); 204280304Sjkim return (-1); 205280304Sjkim } 206280304Sjkim switch (errno) { 207280304Sjkim case EINTEGRITY: 20855714Skris ERROR(disk, "cylinder group checks failed"); 209280304Sjkim break; 210280304Sjkim case EIO: 211280304Sjkim ERROR(disk, "read error from block device"); 212280304Sjkim break; 213280304Sjkim default: 214280304Sjkim ERROR(disk, strerror(errno)); 215280304Sjkim break; 216280304Sjkim } 217 return (-1); 218} 219 220int 221cgget(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 255int 256cgwrite(struct uufsd *disk) 257{ 258 259 return (cgwrite1(disk, disk->d_cg.cg_cgx)); 260} 261 262int 263cgwrite1(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 297int 298cgput(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