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