direct vop calls cleaned up by hand
[unix-history] / usr / src / sys / ufs / lfs / lfs_balloc.c
CommitLineData
da7c5cc6 1/*
9fc995cf 2 * Copyright (c) 1989, 1991 Regents of the University of California.
7188ac27 3 * All rights reserved.
da7c5cc6 4 *
b702c21d 5 * %sccs.include.redist.c%
7188ac27 6 *
8cfb9f42 7 * @(#)lfs_balloc.c 7.29 (Berkeley) %G%
da7c5cc6 8 */
52212483 9
f6437c6d
KB
10#include <sys/param.h>
11#include <sys/buf.h>
12#include <sys/proc.h>
13#include <sys/vnode.h>
14#include <sys/mount.h>
15#include <sys/resourcevar.h>
16#include <sys/specdev.h>
17#include <sys/trace.h>
c6f5111d 18
9fc995cf
KB
19#include <ufs/ufs/quota.h>
20#include <ufs/ufs/inode.h>
21#include <ufs/ufs/ufsmount.h>
f6437c6d 22
9fc995cf
KB
23#include <ufs/lfs/lfs.h>
24#include <ufs/lfs/lfs_extern.h>
52212483 25
bc375a66 26int lfs_getlbns __P((struct vnode *, daddr_t, INDIR *, int *));
1cc06455 27
52212483 28/*
f6437c6d
KB
29 * Bmap converts a the logical block number of a file to its physical block
30 * number on the disk. The conversion is done by using the logical block
31 * number to index into the array of block pointers described by the dinode.
1cc06455
KB
32 */
33int
9342689a
JH
34lfs_bmap (ap)
35 struct vop_bmap_args *ap;
36#define vp (ap->a_vp)
37#define bn (ap->a_bn)
38#define vpp (ap->a_vpp)
39#define bnp (ap->a_bnp)
1cc06455
KB
40{
41#ifdef VERBOSE
42 printf("lfs_bmap\n");
43#endif
44 /*
45 * Check for underlying vnode requests and ensure that logical
46 * to physical mapping is requested.
47 */
48 if (vpp != NULL)
49 *vpp = VTOI(vp)->i_devvp;
50 if (bnp == NULL)
51 return (0);
52
53 return (lfs_bmaparray(vp, bn, bnp, NULL, NULL));
54}
9342689a
JH
55#undef vp
56#undef bn
57#undef vpp
58#undef bnp
1cc06455
KB
59
60/*
fce00cda
KB
61 * LFS has a different version of bmap from FFS because of a naming conflict.
62 * In FFS, meta blocks are given real disk addresses at allocation time, and
63 * are linked into the device vnode, using a logical block number which is
64 * the same as the physical block number. This can't be done by LFS because
65 * blocks aren't given disk addresses until they're written, so there's no
66 * way to distinguish the meta-data blocks for one file from any other file.
67 * This means that meta-data blocks have to be on the vnode for the file so
68 * they can be found, and have to have "names" different from the standard
69 * data blocks. To do this, we divide the name space into positive and
70 * negative block numbers, and give the meta-data blocks negative logical
175a033b
KB
71 * numbers. Indirect blocks are addressed by the negative address of the
72 * first data block to which they point. Double indirect blocks are addressed
73 * by one less than the address of the first indirect block to which they
74 * point. Triple indirect blocks are addressed by one less than the address
75 * of the first double indirect block to which they point.
52212483 76 */
e3b6a940 77int
1cc06455 78lfs_bmaparray(vp, bn, bnp, ap, nump)
8ad16d99 79 struct vnode *vp;
7188ac27 80 register daddr_t bn;
8ad16d99 81 daddr_t *bnp;
1cc06455
KB
82 INDIR *ap;
83 int *nump;
52212483 84{
8cfb9f42 85 USES_VOP_STRATEGY;
8ad16d99 86 register struct inode *ip;
7188ac27 87 struct buf *bp;
1cc06455 88 struct lfs *fs;
fce00cda 89 struct vnode *devvp;
1cc06455
KB
90 INDIR a[NIADDR], *xap;
91 daddr_t *bap, daddr;
92 long metalbn;
93 int error, num, off;
7188ac27 94
d5075120 95
1cc06455 96 ip = VTOI(vp);
fce00cda 97#ifdef VERBOSE
1cc06455
KB
98 printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number);
99#endif
100#ifdef DIAGNOSTIC
101 if (ap != NULL && nump == NULL || ap == NULL && nump != NULL)
102 panic("lfs_bmaparray: invalid arguments");
fce00cda 103#endif
175a033b 104
1cc06455
KB
105 xap = ap == NULL ? a : ap;
106 if (error = lfs_getlbns(vp, bn, xap, nump))
107 return (error);
f6437c6d 108
1cc06455 109 num = *nump;
cb92c035 110
1cc06455
KB
111 if (num == 0) {
112 *bnp = ip->i_db[bn];
113 if (*bnp == 0)
114 *bnp = UNASSIGNED;
115 return (0);
7188ac27 116 }
d5075120 117
cb92c035
KB
118
119 /* Get disk address out of indirect block array */
120 daddr = ip->i_ib[xap->in_off];
121
1cc06455 122 /* Fetch through the indirect blocks. */
cb92c035 123 fs = ip->i_lfs;
d5075120 124 devvp = VFSTOUFS(vp->v_mount)->um_devvp;
175a033b 125
cb92c035
KB
126 for (bp = NULL, ++xap; daddr && --num; ++xap) {
127 /* If looking for a meta-block, break out when we find it. */
128 metalbn = xap->in_lbn;
1cc06455 129 if (metalbn == bn)
175a033b
KB
130 break;
131
fce00cda
KB
132 /*
133 * Read in the appropriate indirect block. LFS can't do a
134 * bread because bread knows that FFS will hand it the device
135 * vnode, not the file vnode, so the b_dev and b_blkno would
136 * be wrong.
137 *
138 * XXX
139 * This REALLY needs to be fixed, at the very least it needs
1cc06455
KB
140 * to be rethought when the buffer cache goes away. When it's
141 * fixed, change lfs_bmaparray and lfs_getlbns to take an ip,
142 * not a vp.
fce00cda 143 */
d5075120 144 if (bp)
7188ac27 145 brelse(bp);
175a033b 146 bp = getblk(vp, metalbn, fs->lfs_bsize);
d5075120 147 if (bp->b_flags & (B_DONE | B_DELWRI)) {
175a033b 148 trace(TR_BREADHIT, pack(vp, size), metalbn);
d5075120 149 } else {
175a033b 150 trace(TR_BREADMISS, pack(vp, size), metalbn);
fce00cda 151 bp->b_blkno = daddr;
175a033b 152 bp->b_flags |= B_READ;
d5075120 153 bp->b_dev = devvp->v_rdev;
8cfb9f42
JH
154 /*
155 * Call a strategy VOP by hand.
156 */
157 vop_strategy_a.a_desc = VDESC(vop_strategy);
158 vop_strategy_a.a_bp=bp;
159 VOCALL(devvp->v_op, VOFFSET(vop_strategy), \
160 &vop_strategy_a);
d5075120
KB
161 curproc->p_stats->p_ru.ru_inblock++; /* XXX */
162 if (error = biowait(bp)) {
163 brelse(bp);
164 return (error);
165 }
7188ac27 166 }
cb92c035 167 daddr = bp->b_un.b_daddr[xap->in_off];
7188ac27 168 }
d5075120
KB
169 if (bp)
170 brelse(bp);
171
cb92c035 172 *bnp = daddr == 0 ? UNASSIGNED : daddr;
7188ac27 173 return (0);
52212483 174}
1cc06455
KB
175
176/*
177 * Create an array of logical block number/offset pairs which represent the
178 * path of indirect blocks required to access a data block. The first "pair"
179 * contains the logical block number of the appropriate single, double or
180 * triple indirect block and the offset into the inode indirect block array.
181 * Note, the logical block number of the inode single/double/triple indirect
182 * block appears twice in the array, once with the offset into the i_ib and
183 * once with the offset into the page itself.
184 */
185int
186lfs_getlbns(vp, bn, ap, nump)
187 struct vnode *vp;
188 register daddr_t bn;
189 INDIR *ap;
190 int *nump;
191{
192 struct lfs *fs;
193 long metalbn, realbn;
194 int j, off, sh;
195
196#ifdef VERBOSE
197 printf("lfs_getlbns: bn %d, inode %d\n", bn, VTOI(vp)->i_number);
198#endif
199 *nump = 0;
200 realbn = bn;
201 if ((long)bn < 0)
202 bn = -(long)bn;
203
204 /* The first NDADDR blocks are direct blocks. */
205 if (bn < NDADDR)
cb92c035 206 return (0);
1cc06455
KB
207
208 /*
209 * Determine the number of levels of indirection. After this loop
210 * is done, sh indicates the number of data blocks possible at the
211 * given level of indirection, and NIADDR - j is the number of levels
212 * of indirection needed to locate the requested block.
213 */
214 bn -= NDADDR;
215 fs = VTOI(vp)->i_lfs;
216 sh = 1;
217 for (j = NIADDR; j > 0; j--) {
218 sh *= NINDIR(fs);
219 if (bn < sh)
220 break;
221 bn -= sh;
222 }
223 if (j == 0)
224 return (EFBIG);
225
226 /* Calculate the address of the first meta-block. */
227 if (realbn >= 0)
228 metalbn = -(realbn - bn + NIADDR - j);
229 else
230 metalbn = -(-realbn - bn + NIADDR - j);
231
232 /*
233 * At each iteration, off is the offset into the bap array which is
234 * an array of disk addresses at the current level of indirection.
235 * The logical block number and the offset in that block are stored
236 * into the argument array.
237 */
238 ++*nump;
239 ap->in_lbn = metalbn;
240 ap->in_off = off = NIADDR - j;
241 ap++;
242 for (; j <= NIADDR; j++) {
243 /* If searching for a meta-data block, quit when found. */
244 if (metalbn == realbn)
245 break;
246
247 sh /= NINDIR(fs);
248 off = (bn / sh) % NINDIR(fs);
249
250 ++*nump;
251 ap->in_lbn = metalbn;
252 ap->in_off = off;
253 ++ap;
254
255 metalbn -= -1 + off * sh;
256 }
257 return (0);
258}
ce90ef66
KB
259
260int
261lfs_balloc(vp, iosize, lbn, bpp)
262 struct vnode *vp;
263 u_long iosize;
264 daddr_t lbn;
265 struct buf **bpp;
266{
9342689a 267 USES_VOP_BMAP;
ce90ef66
KB
268 struct buf *bp;
269 struct inode *ip;
270 struct lfs *fs;
271 daddr_t daddr;
272 int error, newblock;
273
274 ip = VTOI(vp);
275 fs = ip->i_lfs;
276
277 /*
278 * Three cases: it's a block beyond the end of file, it's a block in
279 * the file that may or may not have been assigned a disk address or
280 * we're writing an entire block. Note, if the daddr is unassigned,
281 * the block might still have existed in the cache. If it did, make
282 * sure we don't count it as a new block or zero out its contents.
283 */
284 newblock = ip->i_size <= lbn << fs->lfs_bshift;
9342689a 285 if (!newblock && (error = VOP_BMAP(vp, lbn, NULL, &daddr)))
cb92c035 286 return (error);
ce90ef66 287
843a1a76 288 if (newblock || daddr == UNASSIGNED || iosize == fs->lfs_bsize) {
ce90ef66
KB
289 *bpp = bp = getblk(vp, lbn, fs->lfs_bsize);
290 if (newblock ||
843a1a76 291 daddr == UNASSIGNED && !(bp->b_flags & B_CACHE)) {
ce90ef66
KB
292 ++ip->i_blocks;
293 if (iosize != fs->lfs_bsize)
294 clrbuf(bp);
295 }
cb92c035 296 return (0);
ce90ef66 297 }
cb92c035 298 return (bread(vp, lbn, fs->lfs_bsize, NOCRED, bpp));
ce90ef66
KB
299
300}