15e53a4f9SPedro F. Giffuni /*- 25e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 35e53a4f9SPedro F. Giffuni * 422ec2ef3SJuli Mallett * Copyright (c) 2003 Juli Mallett. All rights reserved. 522ec2ef3SJuli Mallett * 622ec2ef3SJuli Mallett * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the 722ec2ef3SJuli Mallett * FreeBSD project. Redistribution and use in source and binary forms, with 822ec2ef3SJuli Mallett * or without modification, are permitted provided that the following 922ec2ef3SJuli Mallett * conditions are met: 1022ec2ef3SJuli Mallett * 1122ec2ef3SJuli Mallett * 1. Redistribution of source code must retain the above copyright notice, 1222ec2ef3SJuli Mallett * this list of conditions and the following disclaimer. 1322ec2ef3SJuli Mallett * 2. Redistribution in binary form must reproduce the above copyright 1422ec2ef3SJuli Mallett * notice, this list of conditions and the following disclaimer in the 1522ec2ef3SJuli Mallett * documentation and/or other materials provided with the distribution. 1622ec2ef3SJuli Mallett * 1722ec2ef3SJuli Mallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1822ec2ef3SJuli Mallett * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1922ec2ef3SJuli Mallett * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2022ec2ef3SJuli Mallett * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2122ec2ef3SJuli Mallett * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2222ec2ef3SJuli Mallett * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2322ec2ef3SJuli Mallett * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2422ec2ef3SJuli Mallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2522ec2ef3SJuli Mallett * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 2622ec2ef3SJuli Mallett * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2722ec2ef3SJuli Mallett * POSSIBILITY OF SUCH DAMAGE. 2822ec2ef3SJuli Mallett */ 2922ec2ef3SJuli Mallett 3022ec2ef3SJuli Mallett #include <sys/cdefs.h> 3122ec2ef3SJuli Mallett __FBSDID("$FreeBSD$"); 3222ec2ef3SJuli Mallett 3322ec2ef3SJuli Mallett #include <sys/param.h> 3422ec2ef3SJuli Mallett #include <sys/mount.h> 3522ec2ef3SJuli Mallett #include <sys/disklabel.h> 3622ec2ef3SJuli Mallett #include <sys/stat.h> 3722ec2ef3SJuli Mallett 38*d485c77fSKonstantin Belousov #include <ufs/ufs/extattr.h> 39*d485c77fSKonstantin Belousov #include <ufs/ufs/quota.h> 4022ec2ef3SJuli Mallett #include <ufs/ufs/ufsmount.h> 4122ec2ef3SJuli Mallett #include <ufs/ufs/dinode.h> 4222ec2ef3SJuli Mallett #include <ufs/ffs/fs.h> 4322ec2ef3SJuli Mallett 4422ec2ef3SJuli Mallett #include <errno.h> 4522ec2ef3SJuli Mallett #include <fcntl.h> 4622ec2ef3SJuli Mallett #include <stdio.h> 47113db2ddSJeff Roberson #include <stdlib.h> 4822ec2ef3SJuli Mallett #include <string.h> 4922ec2ef3SJuli Mallett #include <unistd.h> 5022ec2ef3SJuli Mallett 5122ec2ef3SJuli Mallett #include <libufs.h> 5222ec2ef3SJuli Mallett 53113db2ddSJeff Roberson ufs2_daddr_t 54113db2ddSJeff Roberson cgballoc(struct uufsd *disk) 55113db2ddSJeff Roberson { 56113db2ddSJeff Roberson u_int8_t *blksfree; 57113db2ddSJeff Roberson struct cg *cgp; 58113db2ddSJeff Roberson struct fs *fs; 59113db2ddSJeff Roberson long bno; 60113db2ddSJeff Roberson 61113db2ddSJeff Roberson fs = &disk->d_fs; 62113db2ddSJeff Roberson cgp = &disk->d_cg; 63113db2ddSJeff Roberson blksfree = cg_blksfree(cgp); 64113db2ddSJeff Roberson for (bno = 0; bno < fs->fs_fpg / fs->fs_frag; bno++) 65113db2ddSJeff Roberson if (ffs_isblock(fs, blksfree, bno)) 66113db2ddSJeff Roberson goto gotit; 67113db2ddSJeff Roberson return (0); 68113db2ddSJeff Roberson gotit: 69113db2ddSJeff Roberson fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 70113db2ddSJeff Roberson ffs_clrblock(fs, blksfree, (long)bno); 71113db2ddSJeff Roberson ffs_clusteracct(fs, cgp, bno, -1); 72113db2ddSJeff Roberson cgp->cg_cs.cs_nbfree--; 73113db2ddSJeff Roberson fs->fs_cstotal.cs_nbfree--; 74113db2ddSJeff Roberson fs->fs_fmod = 1; 75113db2ddSJeff Roberson return (cgbase(fs, cgp->cg_cgx) + blkstofrags(fs, bno)); 76113db2ddSJeff Roberson } 77113db2ddSJeff Roberson 78113db2ddSJeff Roberson int 79113db2ddSJeff Roberson cgbfree(struct uufsd *disk, ufs2_daddr_t bno, long size) 80113db2ddSJeff Roberson { 81113db2ddSJeff Roberson u_int8_t *blksfree; 82113db2ddSJeff Roberson struct fs *fs; 83113db2ddSJeff Roberson struct cg *cgp; 84113db2ddSJeff Roberson ufs1_daddr_t fragno, cgbno; 85113db2ddSJeff Roberson int i, cg, blk, frags, bbase; 86113db2ddSJeff Roberson 87113db2ddSJeff Roberson fs = &disk->d_fs; 88113db2ddSJeff Roberson cg = dtog(fs, bno); 89113db2ddSJeff Roberson if (cgread1(disk, cg) != 1) 90113db2ddSJeff Roberson return (-1); 91113db2ddSJeff Roberson cgp = &disk->d_cg; 92113db2ddSJeff Roberson cgbno = dtogd(fs, bno); 93113db2ddSJeff Roberson blksfree = cg_blksfree(cgp); 94113db2ddSJeff Roberson if (size == fs->fs_bsize) { 95113db2ddSJeff Roberson fragno = fragstoblks(fs, cgbno); 96113db2ddSJeff Roberson ffs_setblock(fs, blksfree, fragno); 97113db2ddSJeff Roberson ffs_clusteracct(fs, cgp, fragno, 1); 98113db2ddSJeff Roberson cgp->cg_cs.cs_nbfree++; 99113db2ddSJeff Roberson fs->fs_cstotal.cs_nbfree++; 100113db2ddSJeff Roberson fs->fs_cs(fs, cg).cs_nbfree++; 101113db2ddSJeff Roberson } else { 102113db2ddSJeff Roberson bbase = cgbno - fragnum(fs, cgbno); 103113db2ddSJeff Roberson /* 104113db2ddSJeff Roberson * decrement the counts associated with the old frags 105113db2ddSJeff Roberson */ 106113db2ddSJeff Roberson blk = blkmap(fs, blksfree, bbase); 107113db2ddSJeff Roberson ffs_fragacct(fs, blk, cgp->cg_frsum, -1); 108113db2ddSJeff Roberson /* 109113db2ddSJeff Roberson * deallocate the fragment 110113db2ddSJeff Roberson */ 111113db2ddSJeff Roberson frags = numfrags(fs, size); 112113db2ddSJeff Roberson for (i = 0; i < frags; i++) 113113db2ddSJeff Roberson setbit(blksfree, cgbno + i); 114113db2ddSJeff Roberson cgp->cg_cs.cs_nffree += i; 115113db2ddSJeff Roberson fs->fs_cstotal.cs_nffree += i; 116113db2ddSJeff Roberson fs->fs_cs(fs, cg).cs_nffree += i; 117113db2ddSJeff Roberson /* 118113db2ddSJeff Roberson * add back in counts associated with the new frags 119113db2ddSJeff Roberson */ 120113db2ddSJeff Roberson blk = blkmap(fs, blksfree, bbase); 121113db2ddSJeff Roberson ffs_fragacct(fs, blk, cgp->cg_frsum, 1); 122113db2ddSJeff Roberson /* 123113db2ddSJeff Roberson * if a complete block has been reassembled, account for it 124113db2ddSJeff Roberson */ 125113db2ddSJeff Roberson fragno = fragstoblks(fs, bbase); 126113db2ddSJeff Roberson if (ffs_isblock(fs, blksfree, fragno)) { 127113db2ddSJeff Roberson cgp->cg_cs.cs_nffree -= fs->fs_frag; 128113db2ddSJeff Roberson fs->fs_cstotal.cs_nffree -= fs->fs_frag; 129113db2ddSJeff Roberson fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 130113db2ddSJeff Roberson ffs_clusteracct(fs, cgp, fragno, 1); 131113db2ddSJeff Roberson cgp->cg_cs.cs_nbfree++; 132113db2ddSJeff Roberson fs->fs_cstotal.cs_nbfree++; 133113db2ddSJeff Roberson fs->fs_cs(fs, cg).cs_nbfree++; 134113db2ddSJeff Roberson } 135113db2ddSJeff Roberson } 136113db2ddSJeff Roberson return cgwrite(disk); 137113db2ddSJeff Roberson } 138113db2ddSJeff Roberson 139113db2ddSJeff Roberson ino_t 140113db2ddSJeff Roberson cgialloc(struct uufsd *disk) 141113db2ddSJeff Roberson { 142113db2ddSJeff Roberson struct ufs2_dinode *dp2; 143113db2ddSJeff Roberson u_int8_t *inosused; 144113db2ddSJeff Roberson struct cg *cgp; 145113db2ddSJeff Roberson struct fs *fs; 146113db2ddSJeff Roberson ino_t ino; 147113db2ddSJeff Roberson int i; 148113db2ddSJeff Roberson 149113db2ddSJeff Roberson fs = &disk->d_fs; 150113db2ddSJeff Roberson cgp = &disk->d_cg; 151113db2ddSJeff Roberson inosused = cg_inosused(cgp); 152b97e003fSEd Maste for (ino = 0; ino < fs->fs_ipg; ino++) 153113db2ddSJeff Roberson if (isclr(inosused, ino)) 154113db2ddSJeff Roberson goto gotit; 155113db2ddSJeff Roberson return (0); 156113db2ddSJeff Roberson gotit: 157113db2ddSJeff Roberson if (fs->fs_magic == FS_UFS2_MAGIC && 158113db2ddSJeff Roberson ino + INOPB(fs) > cgp->cg_initediblk && 159113db2ddSJeff Roberson cgp->cg_initediblk < cgp->cg_niblk) { 160113db2ddSJeff Roberson char block[MAXBSIZE]; 161113db2ddSJeff Roberson bzero(block, (int)fs->fs_bsize); 162113db2ddSJeff Roberson dp2 = (struct ufs2_dinode *)█ 163113db2ddSJeff Roberson for (i = 0; i < INOPB(fs); i++) { 16444444759SPedro F. Giffuni dp2->di_gen = arc4random(); 165113db2ddSJeff Roberson dp2++; 166113db2ddSJeff Roberson } 167113db2ddSJeff Roberson if (bwrite(disk, ino_to_fsba(fs, 168113db2ddSJeff Roberson cgp->cg_cgx * fs->fs_ipg + cgp->cg_initediblk), 169113db2ddSJeff Roberson block, fs->fs_bsize)) 170113db2ddSJeff Roberson return (0); 171113db2ddSJeff Roberson cgp->cg_initediblk += INOPB(fs); 172113db2ddSJeff Roberson } 173113db2ddSJeff Roberson 174113db2ddSJeff Roberson setbit(inosused, ino); 175113db2ddSJeff Roberson cgp->cg_irotor = ino; 176113db2ddSJeff Roberson cgp->cg_cs.cs_nifree--; 177113db2ddSJeff Roberson fs->fs_cstotal.cs_nifree--; 178113db2ddSJeff Roberson fs->fs_cs(fs, cgp->cg_cgx).cs_nifree--; 179113db2ddSJeff Roberson fs->fs_fmod = 1; 180113db2ddSJeff Roberson 181113db2ddSJeff Roberson return (ino + (cgp->cg_cgx * fs->fs_ipg)); 182113db2ddSJeff Roberson } 183113db2ddSJeff Roberson 18422ec2ef3SJuli Mallett int 18522ec2ef3SJuli Mallett cgread(struct uufsd *disk) 18622ec2ef3SJuli Mallett { 18772f854ceSKirk McKusick 18872f854ceSKirk McKusick if (disk->d_ccg >= disk->d_fs.fs_ncg) 18972f854ceSKirk McKusick return (0); 1901081253fSJuli Mallett return (cgread1(disk, disk->d_ccg++)); 19122ec2ef3SJuli Mallett } 19222ec2ef3SJuli Mallett 19385ee267aSKirk McKusick /* Short read/write error messages from cgget()/cgput() */ 19485ee267aSKirk McKusick static const char *failmsg; 19585ee267aSKirk McKusick 19622ec2ef3SJuli Mallett int 19722ec2ef3SJuli Mallett cgread1(struct uufsd *disk, int c) 19822ec2ef3SJuli Mallett { 19972f854ceSKirk McKusick 20085ee267aSKirk McKusick if (cgget(disk->d_fd, &disk->d_fs, c, &disk->d_cg) == 0) { 20185ee267aSKirk McKusick disk->d_lcg = c; 20272f854ceSKirk McKusick return (1); 20385ee267aSKirk McKusick } 20485ee267aSKirk McKusick ERROR(disk, NULL); 20585ee267aSKirk McKusick if (failmsg != NULL) { 20685ee267aSKirk McKusick ERROR(disk, failmsg); 20785ee267aSKirk McKusick return (-1); 20885ee267aSKirk McKusick } 20985ee267aSKirk McKusick switch (errno) { 21085ee267aSKirk McKusick case EINTEGRITY: 21185ee267aSKirk McKusick ERROR(disk, "cylinder group checks failed"); 21285ee267aSKirk McKusick break; 21385ee267aSKirk McKusick case EIO: 21485ee267aSKirk McKusick ERROR(disk, "read error from block device"); 21585ee267aSKirk McKusick break; 21685ee267aSKirk McKusick default: 21785ee267aSKirk McKusick ERROR(disk, strerror(errno)); 21885ee267aSKirk McKusick break; 21985ee267aSKirk McKusick } 22072f854ceSKirk McKusick return (-1); 22172f854ceSKirk McKusick } 22272f854ceSKirk McKusick 22372f854ceSKirk McKusick int 22485ee267aSKirk McKusick cgget(int devfd, struct fs *fs, int cg, struct cg *cgp) 22572f854ceSKirk McKusick { 22672f854ceSKirk McKusick uint32_t cghash, calchash; 22785ee267aSKirk McKusick size_t cnt; 22822ec2ef3SJuli Mallett 22985ee267aSKirk McKusick failmsg = NULL; 23085ee267aSKirk McKusick if ((cnt = pread(devfd, cgp, fs->fs_cgsize, 23185ee267aSKirk McKusick fsbtodb(fs, cgtod(fs, cg)) * (fs->fs_fsize / fsbtodb(fs,1)))) < 0) 23285ee267aSKirk McKusick return (-1); 23385ee267aSKirk McKusick if (cnt == 0) { 23485ee267aSKirk McKusick failmsg = "end of file from block device"; 23585ee267aSKirk McKusick errno = EIO; 23685ee267aSKirk McKusick return (-1); 23785ee267aSKirk McKusick } 23885ee267aSKirk McKusick if (cnt != fs->fs_cgsize) { 23985ee267aSKirk McKusick failmsg = "short read from block device"; 24085ee267aSKirk McKusick errno = EIO; 2411081253fSJuli Mallett return (-1); 24222ec2ef3SJuli Mallett } 24372f854ceSKirk McKusick calchash = cgp->cg_ckhash; 24472f854ceSKirk McKusick if ((fs->fs_metackhash & CK_CYLGRP) != 0) { 24572f854ceSKirk McKusick cghash = cgp->cg_ckhash; 24672f854ceSKirk McKusick cgp->cg_ckhash = 0; 24772f854ceSKirk McKusick calchash = calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize); 24872f854ceSKirk McKusick cgp->cg_ckhash = cghash; 24972f854ceSKirk McKusick } 25072f854ceSKirk McKusick if (cgp->cg_ckhash != calchash || !cg_chkmagic(cgp) || 25172f854ceSKirk McKusick cgp->cg_cgx != cg) { 25285ee267aSKirk McKusick errno = EINTEGRITY; 25372f854ceSKirk McKusick return (-1); 25472f854ceSKirk McKusick } 25572f854ceSKirk McKusick return (0); 25622ec2ef3SJuli Mallett } 257cf4652e7SPawel Jakub Dawidek 258cf4652e7SPawel Jakub Dawidek int 259113db2ddSJeff Roberson cgwrite(struct uufsd *disk) 260113db2ddSJeff Roberson { 26172f854ceSKirk McKusick 26285ee267aSKirk McKusick return (cgwrite1(disk, disk->d_cg.cg_cgx)); 263113db2ddSJeff Roberson } 264113db2ddSJeff Roberson 265113db2ddSJeff Roberson int 26672f854ceSKirk McKusick cgwrite1(struct uufsd *disk, int cg) 26772f854ceSKirk McKusick { 26872f854ceSKirk McKusick static char errmsg[BUFSIZ]; 26972f854ceSKirk McKusick 27085ee267aSKirk McKusick if (cg == disk->d_cg.cg_cgx) { 27185ee267aSKirk McKusick if (cgput(disk->d_fd, &disk->d_fs, &disk->d_cg) == 0) 27285ee267aSKirk McKusick return (0); 27385ee267aSKirk McKusick ERROR(disk, NULL); 27485ee267aSKirk McKusick if (failmsg != NULL) { 27585ee267aSKirk McKusick ERROR(disk, failmsg); 27685ee267aSKirk McKusick return (-1); 27785ee267aSKirk McKusick } 27885ee267aSKirk McKusick switch (errno) { 27985ee267aSKirk McKusick case EIO: 28085ee267aSKirk McKusick ERROR(disk, "unable to write cylinder group"); 28185ee267aSKirk McKusick break; 28285ee267aSKirk McKusick default: 28385ee267aSKirk McKusick ERROR(disk, strerror(errno)); 28485ee267aSKirk McKusick break; 28585ee267aSKirk McKusick } 28685ee267aSKirk McKusick return (-1); 28785ee267aSKirk McKusick } 28872f854ceSKirk McKusick snprintf(errmsg, BUFSIZ, "Cylinder group %d in buffer does not match " 28972f854ceSKirk McKusick "the cylinder group %d that cgwrite1 requested", 29072f854ceSKirk McKusick disk->d_cg.cg_cgx, cg); 29172f854ceSKirk McKusick ERROR(disk, errmsg); 29272f854ceSKirk McKusick errno = EDOOFUS; 29372f854ceSKirk McKusick return (-1); 29472f854ceSKirk McKusick } 29572f854ceSKirk McKusick 29672f854ceSKirk McKusick int 29785ee267aSKirk McKusick cgput(int devfd, struct fs *fs, struct cg *cgp) 298cf4652e7SPawel Jakub Dawidek { 29985ee267aSKirk McKusick size_t cnt; 300cf4652e7SPawel Jakub Dawidek 30175e3597aSKirk McKusick if ((fs->fs_metackhash & CK_CYLGRP) != 0) { 30272f854ceSKirk McKusick cgp->cg_ckhash = 0; 30372f854ceSKirk McKusick cgp->cg_ckhash = 30472f854ceSKirk McKusick calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize); 30575e3597aSKirk McKusick } 30685ee267aSKirk McKusick failmsg = NULL; 30785ee267aSKirk McKusick if ((cnt = pwrite(devfd, cgp, fs->fs_cgsize, 30885ee267aSKirk McKusick fsbtodb(fs, cgtod(fs, cgp->cg_cgx)) * 30985ee267aSKirk McKusick (fs->fs_fsize / fsbtodb(fs,1)))) < 0) 31085ee267aSKirk McKusick return (-1); 31185ee267aSKirk McKusick if (cnt != fs->fs_cgsize) { 31285ee267aSKirk McKusick failmsg = "short write to block device"; 313cf4652e7SPawel Jakub Dawidek return (-1); 314cf4652e7SPawel Jakub Dawidek } 315cf4652e7SPawel Jakub Dawidek return (0); 316cf4652e7SPawel Jakub Dawidek } 317