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