must zero out unused portion of partial blocks when truncating files
[unix-history] / usr / src / sys / ufs / lfs / lfs_balloc.c
CommitLineData
94368568 1/* lfs_balloc.c 6.2 84/08/29 */
52212483 2
94368568
JB
3#include "param.h"
4#include "systm.h"
5#include "conf.h"
6#include "inode.h"
7#include "dir.h"
8#include "user.h"
9#include "buf.h"
10#include "proc.h"
11#include "fs.h"
52212483
BJ
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;
a6e7e3c6 34 daddr_t nb, lbn, *bap, pref, blkpref();
52212483
BJ
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],
4f083fd7
SL
54 blkpref(ip, nb, (int)nb, &ip->i_db[0]),
55 osize, (int)fs->fs_bsize);
ef916aa8
SL
56 if (bp == NULL)
57 return ((daddr_t)-1);
52212483
BJ
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) {
a6e7e3c6 68 nb = ip->i_db[bn];
52212483
BJ
69 if (rwflg == B_READ) {
70 if (nb == 0)
71 return ((daddr_t)-1);
72 goto gotit;
73 }
a6e7e3c6 74 if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) {
52212483
BJ
75 if (nb != 0) {
76 /* consider need to reallocate a frag */
77 osize = fragroundup(fs, blkoff(fs, ip->i_size));
78 nsize = fragroundup(fs, size);
79 if (nsize <= osize)
80 goto gotit;
a6e7e3c6 81 bp = realloccg(ip, nb,
4f083fd7 82 blkpref(ip, bn, (int)bn, &ip->i_db[0]),
52212483
BJ
83 osize, nsize);
84 } else {
a6e7e3c6 85 if (ip->i_size < (bn + 1) * fs->fs_bsize)
52212483
BJ
86 nsize = fragroundup(fs, size);
87 else
88 nsize = fs->fs_bsize;
a6e7e3c6 89 bp = alloc(ip,
4f083fd7 90 blkpref(ip, bn, (int)bn, &ip->i_db[0]),
52212483
BJ
91 nsize);
92 }
93 if (bp == NULL)
94 return ((daddr_t)-1);
95 nb = dbtofsb(fs, bp->b_blkno);
96 if ((ip->i_mode&IFMT) == IFDIR)
97 /*
98 * Write directory blocks synchronously
99 * so they never appear with garbage in
100 * them on the disk.
101 */
102 bwrite(bp);
103 else
104 bdwrite(bp);
a6e7e3c6 105 ip->i_db[bn] = nb;
52212483
BJ
106 ip->i_flag |= IUPD|ICHG;
107 }
108gotit:
a6e7e3c6
KM
109 if (bn < NDADDR - 1) {
110 rablock = fsbtodb(fs, ip->i_db[bn + 1]);
111 rasize = blksize(fs, ip, bn + 1);
52212483
BJ
112 }
113 return (nb);
114 }
115
116 /*
117 * Determine how many levels of indirection.
118 */
a6e7e3c6 119 pref = 0;
52212483 120 sh = 1;
a6e7e3c6 121 lbn = bn;
52212483
BJ
122 bn -= NDADDR;
123 for (j = NIADDR; j>0; j--) {
124 sh *= NINDIR(fs);
125 if (bn < sh)
126 break;
127 bn -= sh;
128 }
129 if (j == 0) {
130 u.u_error = EFBIG;
131 return ((daddr_t)0);
132 }
133
134 /*
135 * fetch the first indirect block
136 */
137 nb = ip->i_ib[NIADDR - j];
138 if (nb == 0) {
a6e7e3c6
KM
139 if (rwflg == B_READ)
140 return ((daddr_t)-1);
4f083fd7
SL
141 pref = blkpref(ip, lbn, 0, (daddr_t *)0);
142 bp = alloc(ip, pref, (int)fs->fs_bsize);
a6e7e3c6 143 if (bp == NULL)
52212483
BJ
144 return ((daddr_t)-1);
145 nb = dbtofsb(fs, bp->b_blkno);
146 /*
147 * Write synchronously so that indirect blocks
148 * never point at garbage.
149 */
150 bwrite(bp);
151 ip->i_ib[NIADDR - j] = nb;
152 ip->i_flag |= IUPD|ICHG;
153 }
154
155 /*
156 * fetch through the indirect blocks
157 */
158 for (; j <= NIADDR; j++) {
4f083fd7 159 bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize);
52212483
BJ
160 if (bp->b_flags & B_ERROR) {
161 brelse(bp);
162 return ((daddr_t)0);
163 }
164 bap = bp->b_un.b_daddr;
165 sh /= NINDIR(fs);
166 i = (bn / sh) % NINDIR(fs);
167 nb = bap[i];
168 if (nb == 0) {
169 if (rwflg==B_READ) {
170 brelse(bp);
171 return ((daddr_t)-1);
172 }
a6e7e3c6
KM
173 if (pref == 0)
174 if (j < NIADDR)
4f083fd7
SL
175 pref = blkpref(ip, lbn, 0,
176 (daddr_t *)0);
a6e7e3c6
KM
177 else
178 pref = blkpref(ip, lbn, i, &bap[0]);
4f083fd7 179 nbp = alloc(ip, pref, (int)fs->fs_bsize);
52212483
BJ
180 if (nbp == NULL) {
181 brelse(bp);
182 return ((daddr_t)-1);
183 }
184 nb = dbtofsb(fs, nbp->b_blkno);
185 if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR)
186 /*
187 * Write synchronously so indirect blocks
188 * never point at garbage and blocks
189 * in directories never contain garbage.
190 */
191 bwrite(nbp);
192 else
193 bdwrite(nbp);
194 bap[i] = nb;
195 bdwrite(bp);
196 } else
197 brelse(bp);
198 }
199
200 /*
201 * calculate read-ahead.
202 */
203 if (i < NINDIR(fs) - 1) {
204 rablock = fsbtodb(fs, bap[i+1]);
205 rasize = fs->fs_bsize;
206 }
207 return (nb);
208}