Commit | Line | Data |
---|---|---|
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 | * |
175a033b | 7 | * @(#)lfs_balloc.c 7.22 (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 BJ |
25 | |
26 | /* | |
f6437c6d KB |
27 | * Bmap converts a the logical block number of a file to its physical block |
28 | * number on the disk. The conversion is done by using the logical block | |
29 | * number to index into the array of block pointers described by the dinode. | |
fce00cda KB |
30 | * |
31 | * LFS has a different version of bmap from FFS because of a naming conflict. | |
32 | * In FFS, meta blocks are given real disk addresses at allocation time, and | |
33 | * are linked into the device vnode, using a logical block number which is | |
34 | * the same as the physical block number. This can't be done by LFS because | |
35 | * blocks aren't given disk addresses until they're written, so there's no | |
36 | * way to distinguish the meta-data blocks for one file from any other file. | |
37 | * This means that meta-data blocks have to be on the vnode for the file so | |
38 | * they can be found, and have to have "names" different from the standard | |
39 | * data blocks. To do this, we divide the name space into positive and | |
40 | * negative block numbers, and give the meta-data blocks negative logical | |
175a033b KB |
41 | * numbers. Indirect blocks are addressed by the negative address of the |
42 | * first data block to which they point. Double indirect blocks are addressed | |
43 | * by one less than the address of the first indirect block to which they | |
44 | * point. Triple indirect blocks are addressed by one less than the address | |
45 | * of the first double indirect block to which they point. | |
52212483 | 46 | */ |
e3b6a940 | 47 | int |
8ad16d99 KM |
48 | lfs_bmap(vp, bn, vpp, bnp) |
49 | struct vnode *vp; | |
7188ac27 | 50 | register daddr_t bn; |
8ad16d99 KM |
51 | struct vnode **vpp; |
52 | daddr_t *bnp; | |
52212483 | 53 | { |
8ad16d99 | 54 | register struct inode *ip; |
9fc995cf | 55 | register struct lfs *fs; |
7188ac27 KM |
56 | register daddr_t nb; |
57 | struct buf *bp; | |
fce00cda | 58 | struct vnode *devvp; |
175a033b KB |
59 | daddr_t *bap, daddr, metalbn; |
60 | long realbn; | |
61 | int error, j, off, sh; | |
7188ac27 | 62 | |
8ad16d99 KM |
63 | /* |
64 | * Check for underlying vnode requests and ensure that logical | |
65 | * to physical mapping is requested. | |
66 | */ | |
67 | ip = VTOI(vp); | |
68 | if (vpp != NULL) | |
69 | *vpp = ip->i_devvp; | |
70 | if (bnp == NULL) | |
71 | return (0); | |
d5075120 | 72 | |
fce00cda KB |
73 | #ifdef VERBOSE |
74 | printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number); | |
75 | #endif | |
175a033b KB |
76 | realbn = bn; |
77 | if ((long)bn < 0) | |
78 | bn = -(long)bn; | |
79 | ||
f6437c6d | 80 | /* The first NDADDR blocks are direct blocks. */ |
7188ac27 KM |
81 | if (bn < NDADDR) { |
82 | nb = ip->i_db[bn]; | |
175a033b | 83 | if (nb == 0) { |
e3b6a940 | 84 | *bnp = UNASSIGNED; |
175a033b KB |
85 | return (0); |
86 | } | |
87 | *bnp = nb; | |
7188ac27 KM |
88 | return (0); |
89 | } | |
f6437c6d | 90 | |
fce00cda | 91 | /* |
fce00cda KB |
92 | * Determine the number of levels of indirection. After this loop |
93 | * is done, sh indicates the number of data blocks possible at the | |
175a033b KB |
94 | * given level of indirection, and NIADDR - j is the number of levels |
95 | * of indirection needed to locate the requested block. | |
fce00cda | 96 | */ |
175a033b | 97 | bn -= NDADDR; |
fce00cda | 98 | fs = ip->i_lfs; |
7188ac27 | 99 | sh = 1; |
7188ac27 KM |
100 | for (j = NIADDR; j > 0; j--) { |
101 | sh *= NINDIR(fs); | |
102 | if (bn < sh) | |
103 | break; | |
104 | bn -= sh; | |
105 | } | |
106 | if (j == 0) | |
107 | return (EFBIG); | |
d5075120 | 108 | |
175a033b KB |
109 | /* Calculate the address of the first meta-block. */ |
110 | if (realbn >= 0) | |
111 | metalbn = -(realbn - bn + NIADDR - j); | |
112 | else | |
113 | metalbn = -(-realbn - bn + NIADDR - j); | |
114 | ||
fce00cda KB |
115 | /* |
116 | * Fetch through the indirect blocks. At each iteration, off is the | |
117 | * offset into the bap array which is an array of disk addresses at | |
118 | * the current level of indirection. | |
119 | */ | |
fce00cda | 120 | bp = NULL; |
d5075120 | 121 | devvp = VFSTOUFS(vp->v_mount)->um_devvp; |
175a033b | 122 | for (off = NIADDR - j, bap = ip->i_ib; j <= NIADDR; j++) { |
fce00cda KB |
123 | /* |
124 | * In LFS, it's possible to have a block appended to a file | |
125 | * for which the meta-blocks have not yet been allocated. | |
126 | * This is a win if the file never gets written or if the | |
127 | * file's growing. | |
128 | */ | |
129 | if ((daddr = bap[off]) == 0) { | |
e3b6a940 | 130 | daddr = UNASSIGNED; |
d5075120 KB |
131 | break; |
132 | } | |
175a033b KB |
133 | |
134 | /* If searching for a meta-data block, quit when found. */ | |
135 | if (metalbn == realbn) | |
136 | break; | |
137 | ||
fce00cda KB |
138 | /* |
139 | * Read in the appropriate indirect block. LFS can't do a | |
140 | * bread because bread knows that FFS will hand it the device | |
141 | * vnode, not the file vnode, so the b_dev and b_blkno would | |
142 | * be wrong. | |
143 | * | |
144 | * XXX | |
145 | * This REALLY needs to be fixed, at the very least it needs | |
146 | * to be rethought when the buffer cache goes away. | |
147 | */ | |
d5075120 | 148 | if (bp) |
7188ac27 | 149 | brelse(bp); |
175a033b | 150 | bp = getblk(vp, metalbn, fs->lfs_bsize); |
d5075120 | 151 | if (bp->b_flags & (B_DONE | B_DELWRI)) { |
175a033b | 152 | trace(TR_BREADHIT, pack(vp, size), metalbn); |
d5075120 | 153 | } else { |
175a033b | 154 | trace(TR_BREADMISS, pack(vp, size), metalbn); |
fce00cda | 155 | bp->b_blkno = daddr; |
175a033b | 156 | bp->b_flags |= B_READ; |
d5075120 | 157 | bp->b_dev = devvp->v_rdev; |
275ca4f0 | 158 | (devvp->v_op->vop_strategy)(bp); |
d5075120 KB |
159 | curproc->p_stats->p_ru.ru_inblock++; /* XXX */ |
160 | if (error = biowait(bp)) { | |
161 | brelse(bp); | |
162 | return (error); | |
163 | } | |
7188ac27 | 164 | } |
175a033b | 165 | |
7188ac27 KM |
166 | bap = bp->b_un.b_daddr; |
167 | sh /= NINDIR(fs); | |
d5075120 | 168 | off = (bn / sh) % NINDIR(fs); |
175a033b | 169 | metalbn -= -1 + off * sh; |
7188ac27 | 170 | } |
d5075120 KB |
171 | if (bp) |
172 | brelse(bp); | |
173 | ||
174 | *bnp = daddr; | |
7188ac27 | 175 | return (0); |
52212483 | 176 | } |