xref: /original-bsd/sys/ufs/ffs/ffs_balloc.c (revision fb9118b1)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)ffs_balloc.c	7.2 (Berkeley) 04/02/87
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "inode.h"
12 #include "dir.h"
13 #include "user.h"
14 #include "buf.h"
15 #include "proc.h"
16 #include "fs.h"
17 
18 /*
19  * Bmap defines the structure of file system storage
20  * by returning the physical block number on a device given the
21  * inode and the logical block number in a file.
22  * When convenient, it also leaves the physical
23  * block number of the next block of the file in rablock
24  * for use in read-ahead.
25  */
26 /*VARARGS3*/
27 daddr_t
28 bmap(ip, bn, rwflg, size)
29 	register struct inode *ip;
30 	daddr_t bn;
31 	int rwflg;
32 	int size;	/* supplied only when rwflg == B_WRITE */
33 {
34 	register int i;
35 	int osize, nsize;
36 	struct buf *bp, *nbp;
37 	struct fs *fs;
38 	int j, sh;
39 	daddr_t nb, lbn, *bap, pref, blkpref();
40 
41 	if (bn < 0) {
42 		u.u_error = EFBIG;
43 		return ((daddr_t)0);
44 	}
45 	fs = ip->i_fs;
46 	rablock = 0;
47 	rasize = 0;		/* conservative */
48 
49 	/*
50 	 * If the next write will extend the file into a new block,
51 	 * and the file is currently composed of a fragment
52 	 * this fragment has to be extended to be a full block.
53 	 */
54 	nb = lblkno(fs, ip->i_size);
55 	if (rwflg == B_WRITE && nb < NDADDR && nb < bn) {
56 		osize = blksize(fs, ip, nb);
57 		if (osize < fs->fs_bsize && osize > 0) {
58 			bp = realloccg(ip, ip->i_db[nb],
59 				blkpref(ip, nb, (int)nb, &ip->i_db[0]),
60 				osize, (int)fs->fs_bsize);
61 			if (bp == NULL)
62 				return ((daddr_t)-1);
63 			ip->i_size = (nb + 1) * fs->fs_bsize;
64 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
65 			ip->i_flag |= IUPD|ICHG;
66 			bdwrite(bp);
67 		}
68 	}
69 	/*
70 	 * The first NDADDR blocks are direct blocks
71 	 */
72 	if (bn < NDADDR) {
73 		nb = ip->i_db[bn];
74 		if (rwflg == B_READ) {
75 			if (nb == 0)
76 				return ((daddr_t)-1);
77 			goto gotit;
78 		}
79 		if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) {
80 			if (nb != 0) {
81 				/* consider need to reallocate a frag */
82 				osize = fragroundup(fs, blkoff(fs, ip->i_size));
83 				nsize = fragroundup(fs, size);
84 				if (nsize <= osize)
85 					goto gotit;
86 				bp = realloccg(ip, nb,
87 					blkpref(ip, bn, (int)bn, &ip->i_db[0]),
88 					osize, nsize);
89 			} else {
90 				if (ip->i_size < (bn + 1) * fs->fs_bsize)
91 					nsize = fragroundup(fs, size);
92 				else
93 					nsize = fs->fs_bsize;
94 				bp = alloc(ip,
95 					blkpref(ip, bn, (int)bn, &ip->i_db[0]),
96 					nsize);
97 			}
98 			if (bp == NULL)
99 				return ((daddr_t)-1);
100 			nb = dbtofsb(fs, bp->b_blkno);
101 			if ((ip->i_mode&IFMT) == IFDIR)
102 				/*
103 				 * Write directory blocks synchronously
104 				 * so they never appear with garbage in
105 				 * them on the disk.
106 				 */
107 				bwrite(bp);
108 			else
109 				bdwrite(bp);
110 			ip->i_db[bn] = nb;
111 			ip->i_flag |= IUPD|ICHG;
112 		}
113 gotit:
114 		if (bn < NDADDR - 1) {
115 			rablock = fsbtodb(fs, ip->i_db[bn + 1]);
116 			rasize = blksize(fs, ip, bn + 1);
117 		}
118 		return (nb);
119 	}
120 
121 	/*
122 	 * Determine how many levels of indirection.
123 	 */
124 	pref = 0;
125 	sh = 1;
126 	lbn = bn;
127 	bn -= NDADDR;
128 	for (j = NIADDR; j>0; j--) {
129 		sh *= NINDIR(fs);
130 		if (bn < sh)
131 			break;
132 		bn -= sh;
133 	}
134 	if (j == 0) {
135 		u.u_error = EFBIG;
136 		return ((daddr_t)0);
137 	}
138 
139 	/*
140 	 * fetch the first indirect block
141 	 */
142 	nb = ip->i_ib[NIADDR - j];
143 	if (nb == 0) {
144 		if (rwflg == B_READ)
145 			return ((daddr_t)-1);
146 		pref = blkpref(ip, lbn, 0, (daddr_t *)0);
147 	        bp = alloc(ip, pref, (int)fs->fs_bsize);
148 		if (bp == NULL)
149 			return ((daddr_t)-1);
150 		nb = dbtofsb(fs, bp->b_blkno);
151 		/*
152 		 * Write synchronously so that indirect blocks
153 		 * never point at garbage.
154 		 */
155 		bwrite(bp);
156 		ip->i_ib[NIADDR - j] = nb;
157 		ip->i_flag |= IUPD|ICHG;
158 	}
159 
160 	/*
161 	 * fetch through the indirect blocks
162 	 */
163 	for (; j <= NIADDR; j++) {
164 		bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize);
165 		if (bp->b_flags & B_ERROR) {
166 			brelse(bp);
167 			return ((daddr_t)0);
168 		}
169 		bap = bp->b_un.b_daddr;
170 		sh /= NINDIR(fs);
171 		i = (bn / sh) % NINDIR(fs);
172 		nb = bap[i];
173 		if (nb == 0) {
174 			if (rwflg==B_READ) {
175 				brelse(bp);
176 				return ((daddr_t)-1);
177 			}
178 			if (pref == 0)
179 				if (j < NIADDR)
180 					pref = blkpref(ip, lbn, 0,
181 						(daddr_t *)0);
182 				else
183 					pref = blkpref(ip, lbn, i, &bap[0]);
184 		        nbp = alloc(ip, pref, (int)fs->fs_bsize);
185 			if (nbp == NULL) {
186 				brelse(bp);
187 				return ((daddr_t)-1);
188 			}
189 			nb = dbtofsb(fs, nbp->b_blkno);
190 			if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR)
191 				/*
192 				 * Write synchronously so indirect blocks
193 				 * never point at garbage and blocks
194 				 * in directories never contain garbage.
195 				 */
196 				bwrite(nbp);
197 			else
198 				bdwrite(nbp);
199 			bap[i] = nb;
200 			bdwrite(bp);
201 		} else
202 			brelse(bp);
203 	}
204 
205 	/*
206 	 * calculate read-ahead.
207 	 */
208 	if (i < NINDIR(fs) - 1) {
209 		rablock = fsbtodb(fs, bap[i+1]);
210 		rasize = fs->fs_bsize;
211 	}
212 	return (nb);
213 }
214