1 /* $OpenBSD: ufs_bmap.c,v 1.37 2021/12/12 09:14:59 visa Exp $ */
2 /* $NetBSD: ufs_bmap.c,v 1.3 1996/02/09 22:36:00 christos Exp $ */
3
4 /*
5 * Copyright (c) 1989, 1991, 1993
6 * The Regents of the University of California. All rights reserved.
7 * (c) UNIX System Laboratories, Inc.
8 * All or some portions of this file are derived from material licensed
9 * to the University of California by American Telephone and Telegraph
10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11 * the permission of UNIX System Laboratories, Inc.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)ufs_bmap.c 8.6 (Berkeley) 1/21/94
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/buf.h>
43 #include <sys/proc.h>
44 #include <sys/vnode.h>
45 #include <sys/mount.h>
46 #include <sys/specdev.h>
47
48 #include <ufs/ufs/quota.h>
49 #include <ufs/ufs/inode.h>
50 #include <ufs/ufs/ufsmount.h>
51 #include <ufs/ufs/ufs_extern.h>
52
53 /*
54 * Bmap converts a the logical block number of a file to its physical block
55 * number on the disk. The conversion is done by using the logical block
56 * number to index into the array of block pointers described by the dinode.
57 */
58 int
ufs_bmap(void * v)59 ufs_bmap(void *v)
60 {
61 struct vop_bmap_args *ap = v;
62
63 /*
64 * Check for underlying vnode requests and ensure that logical
65 * to physical mapping is requested.
66 */
67 if (ap->a_vpp != NULL)
68 *ap->a_vpp = VTOI(ap->a_vp)->i_devvp;
69 if (ap->a_bnp == NULL)
70 return (0);
71
72 return (ufs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL,
73 ap->a_runp));
74 }
75
76 /*
77 * Indirect blocks are now on the vnode for the file. They are given negative
78 * logical block numbers. Indirect blocks are addressed by the negative
79 * address of the first data block to which they point. Double indirect blocks
80 * are addressed by one less than the address of the first indirect block to
81 * which they point. Triple indirect blocks are addressed by one less than
82 * the address of the first double indirect block to which they point.
83 *
84 * ufs_bmaparray does the bmap conversion, and if requested returns the
85 * array of logical blocks which must be traversed to get to a block.
86 * Each entry contains the offset into that block that gets you to the
87 * next block and the disk address of the block (if it is assigned).
88 */
89 int
ufs_bmaparray(struct vnode * vp,daddr_t bn,daddr_t * bnp,struct indir * ap,int * nump,int * runp)90 ufs_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct indir *ap,
91 int *nump, int *runp)
92 {
93 struct inode *ip;
94 struct buf *bp;
95 struct ufsmount *ump;
96 struct mount *mp;
97 struct vnode *devvp;
98 struct indir a[NIADDR+1], *xap;
99 daddr_t daddr, metalbn;
100 int error, maxrun = 0, num;
101
102 ip = VTOI(vp);
103 mp = vp->v_mount;
104 ump = VFSTOUFS(mp);
105 #ifdef DIAGNOSTIC
106 if ((ap != NULL && nump == NULL) || (ap == NULL && nump != NULL))
107 panic("ufs_bmaparray: invalid arguments");
108 #endif
109
110 if (runp) {
111 /*
112 * XXX
113 * If MAXBSIZE is the largest transfer the disks can handle,
114 * we probably want maxrun to be 1 block less so that we
115 * don't create a block larger than the device can handle.
116 */
117 *runp = 0;
118 maxrun = MAXBSIZE / mp->mnt_stat.f_iosize - 1;
119 }
120
121 xap = ap == NULL ? a : ap;
122 if (!nump)
123 nump = #
124 if ((error = ufs_getlbns(vp, bn, xap, nump)) != 0)
125 return (error);
126
127 num = *nump;
128 if (num == 0) {
129 *bnp = blkptrtodb(ump, DIP(ip, db[bn]));
130 if (*bnp == 0)
131 *bnp = -1;
132 else if (runp)
133 for (++bn; bn < NDADDR && *runp < maxrun &&
134 is_sequential(ump, DIP(ip, db[bn - 1]),
135 DIP(ip, db[bn]));
136 ++bn, ++*runp);
137 return (0);
138 }
139
140
141 /* Get disk address out of indirect block array */
142 daddr = DIP(ip, ib[xap->in_off]);
143
144 devvp = VFSTOUFS(vp->v_mount)->um_devvp;
145 for (bp = NULL, ++xap; --num; ++xap) {
146 /*
147 * Exit the loop if there is no disk address assigned yet and
148 * the indirect block isn't in the cache, or if we were
149 * looking for an indirect block and we've found it.
150 */
151
152 metalbn = xap->in_lbn;
153 if ((daddr == 0 && !incore(vp, metalbn)) || metalbn == bn)
154 break;
155 /*
156 * If we get here, we've either got the block in the cache
157 * or we have a disk address for it, go fetch it.
158 */
159 if (bp)
160 brelse(bp);
161
162 xap->in_exists = 1;
163 bp = getblk(vp, metalbn, mp->mnt_stat.f_iosize, 0, INFSLP);
164 if (bp->b_flags & (B_DONE | B_DELWRI)) {
165 ;
166 }
167 #ifdef DIAGNOSTIC
168 else if (!daddr)
169 panic("ufs_bmaparray: indirect block not in cache");
170 #endif
171 else {
172 bp->b_blkno = blkptrtodb(ump, daddr);
173 bp->b_flags |= B_READ;
174 bcstats.pendingreads++;
175 bcstats.numreads++;
176 VOP_STRATEGY(bp->b_vp, bp);
177 curproc->p_ru.ru_inblock++; /* XXX */
178 if ((error = biowait(bp)) != 0) {
179 brelse(bp);
180 return (error);
181 }
182 }
183
184 #ifdef FFS2
185 if (ip->i_ump->um_fstype == UM_UFS2) {
186 daddr = ((int64_t *)bp->b_data)[xap->in_off];
187 if (num == 1 && daddr && runp)
188 for (bn = xap->in_off + 1;
189 bn < MNINDIR(ump) && *runp < maxrun &&
190 is_sequential(ump,
191 ((int64_t *)bp->b_data)[bn - 1],
192 ((int64_t *)bp->b_data)[bn]);
193 ++bn, ++*runp);
194
195 continue;
196 }
197
198 #endif /* FFS2 */
199
200 daddr = ((int32_t *)bp->b_data)[xap->in_off];
201 if (num == 1 && daddr && runp)
202 for (bn = xap->in_off + 1;
203 bn < MNINDIR(ump) && *runp < maxrun &&
204 is_sequential(ump,
205 ((int32_t *)bp->b_data)[bn - 1],
206 ((int32_t *)bp->b_data)[bn]);
207 ++bn, ++*runp);
208 }
209 if (bp)
210 brelse(bp);
211
212 daddr = blkptrtodb(ump, daddr);
213 *bnp = daddr == 0 ? -1 : daddr;
214 return (0);
215 }
216
217 /*
218 * Create an array of logical block number/offset pairs which represent the
219 * path of indirect blocks required to access a data block. The first "pair"
220 * contains the logical block number of the appropriate single, double or
221 * triple indirect block and the offset into the inode indirect block array.
222 * Note, the logical block number of the inode single/double/triple indirect
223 * block appears twice in the array, once with the offset into the i_ffs_ib and
224 * once with the offset into the page itself.
225 */
226 int
ufs_getlbns(struct vnode * vp,daddr_t bn,struct indir * ap,int * nump)227 ufs_getlbns(struct vnode *vp, daddr_t bn, struct indir *ap, int *nump)
228 {
229 daddr_t metalbn, realbn;
230 struct ufsmount *ump;
231 int64_t blockcnt;
232 int i, numlevels, off;
233
234 ump = VFSTOUFS(vp->v_mount);
235 if (nump)
236 *nump = 0;
237 numlevels = 0;
238 realbn = bn;
239 if (bn < 0)
240 bn = -bn;
241
242 #ifdef DIAGNOSTIC
243 if (realbn < 0 && realbn > -NDADDR) {
244 panic ("ufs_getlbns: Invalid indirect block %lld specified",
245 (long long)realbn);
246 }
247 #endif
248
249 /* The first NDADDR blocks are direct blocks. */
250 if (bn < NDADDR)
251 return (0);
252
253 /*
254 * Determine the number of levels of indirection. After this loop
255 * is done, blockcnt indicates the number of data blocks possible
256 * at the given level of indirection, and NIADDR - i is the number
257 * of levels of indirection needed to locate the requested block.
258 */
259 for (blockcnt = 1, i = NIADDR, bn -= NDADDR;; i--, bn -= blockcnt) {
260 if (i == 0)
261 return (EFBIG);
262 blockcnt *= MNINDIR(ump);
263 if (bn < blockcnt)
264 break;
265 }
266
267 /* Calculate the address of the first meta-block. */
268 if (realbn >= 0)
269 metalbn = -(realbn - bn + NIADDR - i);
270 else
271 metalbn = -(-realbn - bn + NIADDR - i);
272
273 /*
274 * At each iteration, off is the offset into the bap array which is
275 * an array of disk addresses at the current level of indirection.
276 * The logical block number and the offset in that block are stored
277 * into the argument array.
278 */
279 ap->in_lbn = metalbn;
280 ap->in_off = off = NIADDR - i;
281 ap->in_exists = 0;
282 ap++;
283 for (++numlevels; i <= NIADDR; i++) {
284 /* If searching for a meta-data block, quit when found. */
285 if (metalbn == realbn)
286 break;
287
288 blockcnt /= MNINDIR(ump);
289 off = (bn / blockcnt) % MNINDIR(ump);
290
291 ++numlevels;
292 ap->in_lbn = metalbn;
293 ap->in_off = off;
294 ap->in_exists = 0;
295 ++ap;
296
297 metalbn -= -1 + off * blockcnt;
298 }
299 #ifdef DIAGNOSTIC
300 if (realbn < 0 && metalbn != realbn) {
301 panic("ufs_getlbns: indirect block %lld not found",
302 (long long)realbn);
303 }
304 #endif
305 if (nump)
306 *nump = numlevels;
307 return (0);
308 }
309