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 *)&block;
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