BSD 4_3 release
[unix-history] / usr / src / sys / sys / ufs_bmap.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
95f51977 6 * @(#)ufs_bmap.c 7.1 (Berkeley) 6/5/86
da7c5cc6 7 */
52212483 8
94368568
JB
9#include "param.h"
10#include "systm.h"
94368568
JB
11#include "inode.h"
12#include "dir.h"
13#include "user.h"
14#include "buf.h"
15#include "proc.h"
16#include "fs.h"
52212483
BJ
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*/
27daddr_t
28bmap(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;
a6e7e3c6 39 daddr_t nb, lbn, *bap, pref, blkpref();
52212483
BJ
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],
4f083fd7
SL
59 blkpref(ip, nb, (int)nb, &ip->i_db[0]),
60 osize, (int)fs->fs_bsize);
ef916aa8
SL
61 if (bp == NULL)
62 return ((daddr_t)-1);
52212483
BJ
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) {
a6e7e3c6 73 nb = ip->i_db[bn];
52212483
BJ
74 if (rwflg == B_READ) {
75 if (nb == 0)
76 return ((daddr_t)-1);
77 goto gotit;
78 }
a6e7e3c6 79 if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) {
52212483
BJ
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;
a6e7e3c6 86 bp = realloccg(ip, nb,
4f083fd7 87 blkpref(ip, bn, (int)bn, &ip->i_db[0]),
52212483
BJ
88 osize, nsize);
89 } else {
a6e7e3c6 90 if (ip->i_size < (bn + 1) * fs->fs_bsize)
52212483
BJ
91 nsize = fragroundup(fs, size);
92 else
93 nsize = fs->fs_bsize;
a6e7e3c6 94 bp = alloc(ip,
4f083fd7 95 blkpref(ip, bn, (int)bn, &ip->i_db[0]),
52212483
BJ
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);
a6e7e3c6 110 ip->i_db[bn] = nb;
52212483
BJ
111 ip->i_flag |= IUPD|ICHG;
112 }
113gotit:
a6e7e3c6
KM
114 if (bn < NDADDR - 1) {
115 rablock = fsbtodb(fs, ip->i_db[bn + 1]);
116 rasize = blksize(fs, ip, bn + 1);
52212483
BJ
117 }
118 return (nb);
119 }
120
121 /*
122 * Determine how many levels of indirection.
123 */
a6e7e3c6 124 pref = 0;
52212483 125 sh = 1;
a6e7e3c6 126 lbn = bn;
52212483
BJ
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) {
a6e7e3c6
KM
144 if (rwflg == B_READ)
145 return ((daddr_t)-1);
4f083fd7
SL
146 pref = blkpref(ip, lbn, 0, (daddr_t *)0);
147 bp = alloc(ip, pref, (int)fs->fs_bsize);
a6e7e3c6 148 if (bp == NULL)
52212483
BJ
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++) {
4f083fd7 164 bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize);
52212483
BJ
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 }
a6e7e3c6
KM
178 if (pref == 0)
179 if (j < NIADDR)
4f083fd7
SL
180 pref = blkpref(ip, lbn, 0,
181 (daddr_t *)0);
a6e7e3c6
KM
182 else
183 pref = blkpref(ip, lbn, i, &bap[0]);
4f083fd7 184 nbp = alloc(ip, pref, (int)fs->fs_bsize);
52212483
BJ
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}