xref: /freebsd/lib/libufs/cgroup.c (revision edf8578117e8844e02c0121147f45e4609b30680)
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/extattr.h>
37 #include <ufs/ufs/quota.h>
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 /* Short read/write error messages from cgget()/cgput() */
192 static const char *failmsg;
193 
194 int
195 cgread1(struct uufsd *disk, int c)
196 {
197 
198 	if (cgget(disk->d_fd, &disk->d_fs, c, &disk->d_cg) == 0) {
199 		disk->d_lcg = c;
200 		return (1);
201 	}
202 	ERROR(disk, NULL);
203 	if (failmsg != NULL) {
204 		ERROR(disk, failmsg);
205 		return (-1);
206 	}
207 	switch (errno) {
208 	case EINTEGRITY:
209 		ERROR(disk, "cylinder group checks failed");
210 		break;
211 	case EIO:
212 		ERROR(disk, "read error from block device");
213 		break;
214 	default:
215 		ERROR(disk, strerror(errno));
216 		break;
217 	}
218 	return (-1);
219 }
220 
221 int
222 cgget(int devfd, struct fs *fs, int cg, struct cg *cgp)
223 {
224 	uint32_t cghash, calchash;
225 	size_t cnt;
226 
227 	failmsg = NULL;
228 	if ((cnt = pread(devfd, cgp, fs->fs_cgsize,
229 	    fsbtodb(fs, cgtod(fs, cg)) * (fs->fs_fsize / fsbtodb(fs,1)))) < 0)
230 		return (-1);
231 	if (cnt == 0) {
232 		failmsg = "end of file from block device";
233 		errno = EIO;
234 		return (-1);
235 	}
236 	if (cnt != fs->fs_cgsize) {
237 		failmsg = "short read from block device";
238 		errno = EIO;
239 		return (-1);
240 	}
241 	calchash = cgp->cg_ckhash;
242 	if ((fs->fs_metackhash & CK_CYLGRP) != 0) {
243 		cghash = cgp->cg_ckhash;
244 		cgp->cg_ckhash = 0;
245 		calchash = calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize);
246 		cgp->cg_ckhash = cghash;
247 	}
248 	if (cgp->cg_ckhash != calchash || !cg_chkmagic(cgp) ||
249 	    cgp->cg_cgx != cg) {
250 		errno = EINTEGRITY;
251 		return (-1);
252 	}
253 	return (0);
254 }
255 
256 int
257 cgwrite(struct uufsd *disk)
258 {
259 
260 	return (cgwrite1(disk, disk->d_cg.cg_cgx));
261 }
262 
263 int
264 cgwrite1(struct uufsd *disk, int cg)
265 {
266 	static char errmsg[BUFSIZ];
267 
268 	if (cg == disk->d_cg.cg_cgx) {
269 		if (ufs_disk_write(disk) == -1) {
270 			ERROR(disk, "failed to open disk for writing");
271 			return (-1);
272 		}
273 		if (cgput(disk->d_fd, &disk->d_fs, &disk->d_cg) == 0)
274 			return (0);
275 		ERROR(disk, NULL);
276 		if (failmsg != NULL) {
277 			ERROR(disk, failmsg);
278 			return (-1);
279 		}
280 		switch (errno) {
281 		case EIO:
282 			ERROR(disk, "unable to write cylinder group");
283 			break;
284 		default:
285 			ERROR(disk, strerror(errno));
286 			break;
287 		}
288 		return (-1);
289 	}
290 	snprintf(errmsg, BUFSIZ, "Cylinder group %d in buffer does not match "
291 	    "the cylinder group %d that cgwrite1 requested",
292 	    disk->d_cg.cg_cgx, cg);
293 	ERROR(disk, errmsg);
294 	errno = EDOOFUS;
295 	return (-1);
296 }
297 
298 int
299 cgput(int devfd, struct fs *fs, struct cg *cgp)
300 {
301 	size_t cnt;
302 
303 	if ((fs->fs_metackhash & CK_CYLGRP) != 0) {
304 		cgp->cg_ckhash = 0;
305 		cgp->cg_ckhash =
306 		    calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize);
307 	}
308 	failmsg = NULL;
309 	if ((cnt = pwrite(devfd, cgp, fs->fs_cgsize,
310 	    fsbtodb(fs, cgtod(fs, cgp->cg_cgx)) *
311 	    (fs->fs_fsize / fsbtodb(fs,1)))) < 0)
312 		return (-1);
313 	if (cnt != fs->fs_cgsize) {
314 		failmsg = "short write to block device";
315 		return (-1);
316 	}
317 	return (0);
318 }
319