readdir now returns an eof indication
[unix-history] / usr / src / sys / ufs / lfs / lfs_balloc.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * @(#)lfs_balloc.c 7.7 (Berkeley) %G%
18 */
19
20#include "param.h"
21#include "systm.h"
22#include "user.h"
23#include "buf.h"
24#include "proc.h"
25#include "file.h"
26#include "vnode.h"
27#include "../ufs/inode.h"
28#include "../ufs/fs.h"
29
30/*
31 * Bmap defines the structure of file system storage
32 * by returning the physical block number on a device
33 * given the inode and the logical block number in a file.
34 */
35bmap(ip, bn, bnp)
36 register struct inode *ip;
37 register daddr_t bn;
38 daddr_t *bnp;
39{
40 register struct fs *fs;
41 register daddr_t nb;
42 struct buf *bp;
43 daddr_t *bap;
44 int i, j, sh;
45 int error;
46
47 if (bn < 0)
48 return (EFBIG);
49 fs = ip->i_fs;
50
51 /*
52 * The first NDADDR blocks are direct blocks
53 */
54 if (bn < NDADDR) {
55 nb = ip->i_db[bn];
56 if (nb == 0) {
57 *bnp = (daddr_t)-1;
58 return (0);
59 }
60 *bnp = fsbtodb(fs, nb);
61 return (0);
62 }
63 /*
64 * Determine the number of levels of indirection.
65 */
66 sh = 1;
67 bn -= NDADDR;
68 for (j = NIADDR; j > 0; j--) {
69 sh *= NINDIR(fs);
70 if (bn < sh)
71 break;
72 bn -= sh;
73 }
74 if (j == 0)
75 return (EFBIG);
76 /*
77 * Fetch through the indirect blocks.
78 */
79 nb = ip->i_ib[NIADDR - j];
80 if (nb == 0) {
81 *bnp = (daddr_t)-1;
82 return (0);
83 }
84 for (; j <= NIADDR; j++) {
85 if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
86 (int)fs->fs_bsize, NOCRED, &bp)) {
87 brelse(bp);
88 return (error);
89 }
90 bap = bp->b_un.b_daddr;
91 sh /= NINDIR(fs);
92 i = (bn / sh) % NINDIR(fs);
93 nb = bap[i];
94 if (nb == 0) {
95 *bnp = (daddr_t)-1;
96 brelse(bp);
97 return (0);
98 }
99 brelse(bp);
100 }
101 *bnp = fsbtodb(fs, nb);
102 return (0);
103}
104
105/*
106 * Balloc defines the structure of file system storage
107 * by allocating the physical blocks on a device given
108 * the inode and the logical block number in a file.
109 */
110balloc(ip, bn, size, bpp, flags)
111 register struct inode *ip;
112 register daddr_t bn;
113 int size;
114 struct buf **bpp;
115 int flags;
116{
117 register struct fs *fs;
118 register daddr_t nb;
119 struct buf *bp, *nbp;
120 struct vnode *vp = ITOV(ip);
121 int osize, nsize, i, j, sh, error;
122 daddr_t newb, lbn, *bap, pref, blkpref();
123
124 *bpp = (struct buf *)0;
125 if (bn < 0)
126 return (EFBIG);
127 fs = ip->i_fs;
128
129 /*
130 * If the next write will extend the file into a new block,
131 * and the file is currently composed of a fragment
132 * this fragment has to be extended to be a full block.
133 */
134 nb = lblkno(fs, ip->i_size);
135 if (nb < NDADDR && nb < bn) {
136 osize = blksize(fs, ip, nb);
137 if (osize < fs->fs_bsize && osize > 0) {
138 error = realloccg(ip, nb,
139 blkpref(ip, nb, (int)nb, &ip->i_db[0]),
140 osize, (int)fs->fs_bsize, &bp);
141 if (error)
142 return (error);
143 ip->i_size = (nb + 1) * fs->fs_bsize;
144 ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
145 ip->i_flag |= IUPD|ICHG;
146 if (flags & B_SYNC)
147 bwrite(bp);
148 else
149 bawrite(bp);
150 }
151 }
152 /*
153 * The first NDADDR blocks are direct blocks
154 */
155 if (bn < NDADDR) {
156 nb = ip->i_db[bn];
157 if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) {
158 error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp);
159 if (error) {
160 brelse(bp);
161 return (error);
162 }
163 *bpp = bp;
164 return (0);
165 }
166 if (nb != 0) {
167 /*
168 * Consider need to reallocate a fragment.
169 */
170 osize = fragroundup(fs, blkoff(fs, ip->i_size));
171 nsize = fragroundup(fs, size);
172 if (nsize <= osize) {
173 error = bread(vp, bn, osize, NOCRED, &bp);
174 if (error) {
175 brelse(bp);
176 return (error);
177 }
178 } else {
179 error = realloccg(ip, bn,
180 blkpref(ip, bn, (int)bn, &ip->i_db[0]),
181 osize, nsize, &bp);
182 if (error)
183 return (error);
184 }
185 } else {
186 if (ip->i_size < (bn + 1) * fs->fs_bsize)
187 nsize = fragroundup(fs, size);
188 else
189 nsize = fs->fs_bsize;
190 error = alloc(ip, bn,
191 blkpref(ip, bn, (int)bn, &ip->i_db[0]),
192 nsize, &newb);
193 if (error)
194 return (error);
195 bp = getblk(vp, bn, nsize);
196 bp->b_blkno = fsbtodb(fs, newb);
197 if (flags & B_CLRBUF)
198 clrbuf(bp);
199 }
200 ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
201 ip->i_flag |= IUPD|ICHG;
202 *bpp = bp;
203 return (0);
204 }
205 /*
206 * Determine the number of levels of indirection.
207 */
208 pref = 0;
209 sh = 1;
210 lbn = bn;
211 bn -= NDADDR;
212 for (j = NIADDR; j > 0; j--) {
213 sh *= NINDIR(fs);
214 if (bn < sh)
215 break;
216 bn -= sh;
217 }
218 if (j == 0)
219 return (EFBIG);
220 /*
221 * Fetch the first indirect block allocating if necessary.
222 */
223 nb = ip->i_ib[NIADDR - j];
224 if (nb == 0) {
225 pref = blkpref(ip, lbn, 0, (daddr_t *)0);
226 if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb))
227 return (error);
228 nb = newb;
229 bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
230 clrbuf(bp);
231 /*
232 * Write synchronously so that indirect blocks
233 * never point at garbage.
234 */
235 if (error = bwrite(bp)) {
236 blkfree(ip, nb, fs->fs_bsize);
237 return (error);
238 }
239 ip->i_ib[NIADDR - j] = nb;
240 ip->i_flag |= IUPD|ICHG;
241 }
242 /*
243 * Fetch through the indirect blocks, allocating as necessary.
244 */
245 for (; ; j++) {
246 error = bread(ip->i_devvp, fsbtodb(fs, nb),
247 (int)fs->fs_bsize, NOCRED, &bp);
248 if (error) {
249 brelse(bp);
250 return (error);
251 }
252 bap = bp->b_un.b_daddr;
253 sh /= NINDIR(fs);
254 i = (bn / sh) % NINDIR(fs);
255 nb = bap[i];
256 if (j == NIADDR)
257 break;
258 if (nb != 0) {
259 brelse(bp);
260 continue;
261 }
262 if (pref == 0)
263 pref = blkpref(ip, lbn, 0, (daddr_t *)0);
264 if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
265 brelse(bp);
266 return (error);
267 }
268 nb = newb;
269 nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
270 clrbuf(nbp);
271 /*
272 * Write synchronously so that indirect blocks
273 * never point at garbage.
274 */
275 if (error = bwrite(nbp)) {
276 blkfree(ip, nb, fs->fs_bsize);
277 brelse(bp);
278 return (error);
279 }
280 bap[i] = nb;
281 /*
282 * If required, write synchronously, otherwise use
283 * delayed write. If this is the first instance of
284 * the delayed write, reassociate the buffer with the
285 * file so it will be written if the file is sync'ed.
286 */
287 if (flags & B_SYNC) {
288 bwrite(bp);
289 } else if (bp->b_flags & B_DELWRI) {
290 bdwrite(bp);
291 } else {
292 bdwrite(bp);
293 reassignbuf(bp, vp);
294 }
295 }
296 /*
297 * Get the data block, allocating if necessary.
298 */
299 if (nb == 0) {
300 pref = blkpref(ip, lbn, i, &bap[0]);
301 if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
302 brelse(bp);
303 return (error);
304 }
305 nb = newb;
306 nbp = getblk(vp, lbn, fs->fs_bsize);
307 nbp->b_blkno = fsbtodb(fs, nb);
308 if (flags & B_CLRBUF)
309 clrbuf(nbp);
310 bap[i] = nb;
311 /*
312 * If required, write synchronously, otherwise use
313 * delayed write. If this is the first instance of
314 * the delayed write, reassociate the buffer with the
315 * file so it will be written if the file is sync'ed.
316 */
317 if (flags & B_SYNC) {
318 bwrite(bp);
319 } else if (bp->b_flags & B_DELWRI) {
320 bdwrite(bp);
321 } else {
322 bdwrite(bp);
323 reassignbuf(bp, vp);
324 }
325 *bpp = nbp;
326 return (0);
327 }
328 brelse(bp);
329 nbp = getblk(vp, lbn, fs->fs_bsize);
330 nbp->b_blkno = fsbtodb(fs, nb);
331 if ((flags & B_CLRBUF) && (nbp->b_flags & (B_DONE|B_DELWRI)) == 0) {
332 brelse(nbp);
333 error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
334 if (error) {
335 brelse(nbp);
336 return (error);
337 }
338 }
339 *bpp = nbp;
340 return (0);
341}