xref: /original-bsd/sys/kern/subr_xxx.c (revision 2f60f4d7)
1 /*	subr_xxx.c	4.11	82/06/07	*/
2 
3 /* merged into kernel:	@(#)subr.c 2.2 4/8/82 */
4 
5 #include "../h/param.h"
6 #include "../h/systm.h"
7 #include "../h/conf.h"
8 #include "../h/inode.h"
9 #include "../h/dir.h"
10 #include "../h/user.h"
11 #include "../h/buf.h"
12 #include "../h/proc.h"
13 #include "../h/fs.h"
14 
15 /*
16  * Bmap defines the structure of file system storage
17  * by returning the physical block number on a device given the
18  * inode and the logical block number in a file.
19  * When convenient, it also leaves the physical
20  * block number of the next block of the file in rablock
21  * for use in read-ahead.
22  */
23 /*VARARGS3*/
24 daddr_t
25 bmap(ip, bn, rwflg, size)
26 	register struct inode *ip;
27 	daddr_t bn;
28 	int rwflg;
29 	int size;	/* supplied only when rwflg == B_WRITE */
30 {
31 	register int i;
32 	int osize, nsize;
33 	struct buf *bp, *nbp;
34 	struct fs *fs;
35 	int j, sh;
36 	daddr_t nb, *bap, pref, blkpref();
37 
38 	if (bn < 0) {
39 		u.u_error = EFBIG;
40 		return ((daddr_t)0);
41 	}
42 	fs = ip->i_fs;
43 	rablock = 0;
44 	rasize = 0;		/* conservative */
45 
46 	/*
47 	 * If the next write will extend the file into a new block,
48 	 * and the file is currently composed of a fragment
49 	 * this fragment has to be extended to be a full block.
50 	 */
51 	nb = lblkno(fs, ip->i_size);
52 	if (rwflg == B_WRITE && nb < NDADDR && nb < bn) {
53 		osize = blksize(fs, ip, nb);
54 		if (osize < fs->fs_bsize && osize > 0) {
55 			bp = realloccg(ip, ip->i_db[nb],
56 				nb == 0 ? 0 : ip->i_db[nb - 1] + fs->fs_frag,
57 				osize, fs->fs_bsize);
58 			ip->i_size = (nb + 1) * fs->fs_bsize;
59 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
60 			ip->i_flag |= IUPD|ICHG;
61 			bdwrite(bp);
62 		}
63 	}
64 	/*
65 	 * The first NDADDR blocks are direct blocks
66 	 */
67 	if (bn < NDADDR) {
68 		i = bn;
69 		nb = ip->i_db[i];
70 		if (rwflg == B_READ) {
71 			if (nb == 0)
72 				return ((daddr_t)-1);
73 			goto gotit;
74 		}
75 		if (nb == 0 || ip->i_size < (i + 1) * fs->fs_bsize) {
76 			if (nb != 0) {
77 				/* consider need to reallocate a frag */
78 				osize = fragroundup(fs, blkoff(fs, ip->i_size));
79 				nsize = fragroundup(fs, size);
80 				if (nsize <= osize)
81 					goto gotit;
82 				bp = realloccg(ip, nb, i == 0 ?
83 					0 : ip->i_db[i - 1] + fs->fs_frag,
84 					osize, nsize);
85 			} else {
86 				if (ip->i_size < (i + 1) * fs->fs_bsize)
87 					nsize = fragroundup(fs, size);
88 				else
89 					nsize = fs->fs_bsize;
90 				bp = alloc(ip, i > 0 ?
91 					ip->i_db[i - 1] + fs->fs_frag : 0,
92 					nsize);
93 			}
94 			if (bp == NULL)
95 				return ((daddr_t)-1);
96 			nb = dbtofsb(fs, bp->b_blkno);
97 			if ((ip->i_mode&IFMT) == IFDIR)
98 				/*
99 				 * Write directory blocks synchronously
100 				 * so they never appear with garbage in
101 				 * them on the disk.
102 				 */
103 				bwrite(bp);
104 			else
105 				bdwrite(bp);
106 			ip->i_db[i] = nb;
107 			ip->i_flag |= IUPD|ICHG;
108 		}
109 gotit:
110 		if (i < NDADDR - 1) {
111 			rablock = fsbtodb(fs, ip->i_db[i+1]);
112 			rasize = blksize(fs, ip, i+1);
113 		}
114 		return (nb);
115 	}
116 
117 	/*
118 	 * Determine how many levels of indirection.
119 	 */
120 	sh = 1;
121 	bn -= NDADDR;
122 	for (j = NIADDR; j>0; j--) {
123 		sh *= NINDIR(fs);
124 		if (bn < sh)
125 			break;
126 		bn -= sh;
127 	}
128 	if (j == 0) {
129 		u.u_error = EFBIG;
130 		return ((daddr_t)0);
131 	}
132 
133 	/*
134 	 * fetch the first indirect block
135 	 */
136 	nb = ip->i_ib[NIADDR - j];
137 	if (nb == 0) {
138 		if (rwflg==B_READ ||
139 		    (bp = alloc(ip, (daddr_t)0, fs->fs_bsize)) == NULL)
140 			return ((daddr_t)-1);
141 		nb = dbtofsb(fs, bp->b_blkno);
142 		/*
143 		 * Write synchronously so that indirect blocks
144 		 * never point at garbage.
145 		 */
146 		bwrite(bp);
147 		ip->i_ib[NIADDR - j] = nb;
148 		ip->i_flag |= IUPD|ICHG;
149 	}
150 
151 	/*
152 	 * fetch through the indirect blocks
153 	 */
154 	for (; j <= NIADDR; j++) {
155 		bp = bread(ip->i_dev, fsbtodb(fs, nb), fs->fs_bsize);
156 		if (bp->b_flags & B_ERROR) {
157 			brelse(bp);
158 			return ((daddr_t)0);
159 		}
160 		bap = bp->b_un.b_daddr;
161 		sh /= NINDIR(fs);
162 		i = (bn / sh) % NINDIR(fs);
163 		nb = bap[i];
164 		if (nb == 0) {
165 			if (rwflg==B_READ) {
166 				brelse(bp);
167 				return ((daddr_t)-1);
168 			}
169 			if (i % (fs->fs_fsize / sizeof(daddr_t)) == 0 ||
170 			    bap[i - 1] == 0)
171 				pref = blkpref(ip->i_fs);
172 			else
173 				pref = bap[i - 1] + fs->fs_frag;
174 		        nbp = alloc(ip, pref, fs->fs_bsize);
175 			if (nbp == NULL) {
176 				brelse(bp);
177 				return ((daddr_t)-1);
178 			}
179 			nb = dbtofsb(fs, nbp->b_blkno);
180 			if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR)
181 				/*
182 				 * Write synchronously so indirect blocks
183 				 * never point at garbage and blocks
184 				 * in directories never contain garbage.
185 				 */
186 				bwrite(nbp);
187 			else
188 				bdwrite(nbp);
189 			bap[i] = nb;
190 			bdwrite(bp);
191 		} else
192 			brelse(bp);
193 	}
194 
195 	/*
196 	 * calculate read-ahead.
197 	 */
198 	if (i < NINDIR(fs) - 1) {
199 		rablock = fsbtodb(fs, bap[i+1]);
200 		rasize = fs->fs_bsize;
201 	}
202 	return (nb);
203 }
204 
205 /*
206  * Pass back  c  to the user at his location u_base;
207  * update u_base, u_count, and u_offset.  Return -1
208  * on the last character of the user's read.
209  * u_base is in the user address space unless u_segflg is set.
210  */
211 passc(c)
212 register c;
213 {
214 	register id;
215 
216 	if ((id = u.u_segflg) == 1)
217 		*u.u_base = c;
218 	else
219 		if (id?suibyte(u.u_base, c):subyte(u.u_base, c) < 0) {
220 			u.u_error = EFAULT;
221 			return (-1);
222 		}
223 	u.u_count--;
224 	u.u_offset++;
225 	u.u_base++;
226 	return (u.u_count == 0? -1: 0);
227 }
228 
229 #include "ct.h"
230 #if NCT > 0
231 /*
232  * Pick up and return the next character from the user's
233  * write call at location u_base;
234  * update u_base, u_count, and u_offset.  Return -1
235  * when u_count is exhausted.  u_base is in the user's
236  * address space unless u_segflg is set.
237  */
238 cpass()
239 {
240 	register c, id;
241 
242 	if (u.u_count == 0)
243 		return (-1);
244 	if ((id = u.u_segflg) == 1)
245 		c = *u.u_base;
246 	else
247 		if ((c = id==0?fubyte(u.u_base):fuibyte(u.u_base)) < 0) {
248 			u.u_error = EFAULT;
249 			return (-1);
250 		}
251 	u.u_count--;
252 	u.u_offset++;
253 	u.u_base++;
254 	return (c&0377);
255 }
256 #endif
257 
258 /*
259  * Routine which sets a user error; placed in
260  * illegal entries in the bdevsw and cdevsw tables.
261  */
262 nodev()
263 {
264 
265 	u.u_error = ENODEV;
266 }
267 
268 /*
269  * Null routine; placed in insignificant entries
270  * in the bdevsw and cdevsw tables.
271  */
272 nulldev()
273 {
274 
275 }
276 
277 imin(a, b)
278 {
279 
280 	return (a < b ? a : b);
281 }
282 
283 imax(a, b)
284 {
285 
286 	return (a > b ? a : b);
287 }
288 
289 unsigned
290 min(a, b)
291 	unsigned int a, b;
292 {
293 
294 	return (a < b ? a : b);
295 }
296 
297 unsigned
298 max(a, b)
299 	unsigned int a, b;
300 {
301 
302 	return (a > b ? a : b);
303 }
304 
305 struct proc *
306 pfind(pid)
307 	int pid;
308 {
309 	register struct proc *p;
310 
311 	for (p = &proc[pidhash[PIDHASH(pid)]]; p != &proc[0]; p = &proc[p->p_idhash])
312 		if (p->p_pid == pid)
313 			return (p);
314 	return ((struct proc *)0);
315 }
316