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