]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
5d5c5d0d A |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. |
3 | * | |
6601e61a | 4 | * @APPLE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
6601e61a A |
6 | * The contents of this file constitute Original Code as defined in and |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
8f6c56a5 | 11 | * |
6601e61a A |
12 | * This Original Code and all software distributed under the License are |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
6601e61a A |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
8f6c56a5 | 19 | * |
6601e61a | 20 | * @APPLE_LICENSE_HEADER_END@ |
1c79356b A |
21 | */ |
22 | /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ | |
23 | /* | |
24 | * Copyright (c) 1989, 1991, 1993 | |
25 | * The Regents of the University of California. All rights reserved. | |
26 | * (c) UNIX System Laboratories, Inc. | |
27 | * All or some portions of this file are derived from material licensed | |
28 | * to the University of California by American Telephone and Telegraph | |
29 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
30 | * the permission of UNIX System Laboratories, Inc. | |
31 | * | |
32 | * Redistribution and use in source and binary forms, with or without | |
33 | * modification, are permitted provided that the following conditions | |
34 | * are met: | |
35 | * 1. Redistributions of source code must retain the above copyright | |
36 | * notice, this list of conditions and the following disclaimer. | |
37 | * 2. Redistributions in binary form must reproduce the above copyright | |
38 | * notice, this list of conditions and the following disclaimer in the | |
39 | * documentation and/or other materials provided with the distribution. | |
40 | * 3. All advertising materials mentioning features or use of this software | |
41 | * must display the following acknowledgement: | |
42 | * This product includes software developed by the University of | |
43 | * California, Berkeley and its contributors. | |
44 | * 4. Neither the name of the University nor the names of its contributors | |
45 | * may be used to endorse or promote products derived from this software | |
46 | * without specific prior written permission. | |
47 | * | |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
58 | * SUCH DAMAGE. | |
59 | * | |
60 | * @(#)ufs_bmap.c 8.7 (Berkeley) 3/21/95 | |
61 | */ | |
62 | /* | |
63 | * HISTORY | |
64 | * 11-July-97 Umesh Vaishampayan (umeshv@apple.com) | |
65 | * Cleanup. Fixed compilation error when tracing is turned on. | |
66 | */ | |
67 | #include <rev_endian_fs.h> | |
68 | #include <sys/param.h> | |
69 | #include <sys/buf.h> | |
91447636 A |
70 | #include <sys/proc_internal.h> /* for p_stats */ |
71 | #include <sys/vnode_internal.h> | |
72 | #include <sys/mount_internal.h> | |
1c79356b A |
73 | #include <sys/resourcevar.h> |
74 | #include <sys/trace.h> | |
9bccf70c | 75 | #include <sys/quota.h> |
1c79356b A |
76 | |
77 | #include <miscfs/specfs/specdev.h> | |
78 | ||
79 | #include <ufs/ufs/quota.h> | |
80 | #include <ufs/ufs/inode.h> | |
81 | #include <ufs/ufs/ufsmount.h> | |
82 | #include <ufs/ufs/ufs_extern.h> | |
83 | #if REV_ENDIAN_FS | |
84 | #include <ufs/ufs/ufs_byte_order.h> | |
0c530ab8 | 85 | #include <libkern/OSByteOrder.h> |
1c79356b A |
86 | #endif /* REV_ENDIAN_FS */ |
87 | ||
1c79356b A |
88 | |
89 | /* | |
90 | * Indirect blocks are now on the vnode for the file. They are given negative | |
91 | * logical block numbers. Indirect blocks are addressed by the negative | |
92 | * address of the first data block to which they point. Double indirect blocks | |
93 | * are addressed by one less than the address of the first indirect block to | |
94 | * which they point. Triple indirect blocks are addressed by one less than | |
95 | * the address of the first double indirect block to which they point. | |
96 | * | |
97 | * ufs_bmaparray does the bmap conversion, and if requested returns the | |
98 | * array of logical blocks which must be traversed to get to a block. | |
99 | * Each entry contains the offset into that block that gets you to the | |
100 | * next block and the disk address of the block (if it is assigned). | |
101 | */ | |
102 | ||
103 | int | |
104 | ufs_bmaparray(vp, bn, bnp, ap, nump, runp) | |
91447636 | 105 | vnode_t vp; |
1c79356b A |
106 | ufs_daddr_t bn; |
107 | ufs_daddr_t *bnp; | |
108 | struct indir *ap; | |
109 | int *nump; | |
110 | int *runp; | |
111 | { | |
112 | register struct inode *ip; | |
113 | struct buf *bp; | |
114 | struct ufsmount *ump; | |
115 | struct mount *mp; | |
116 | struct vnode *devvp; | |
117 | struct indir a[NIADDR], *xap; | |
118 | ufs_daddr_t daddr; | |
119 | long metalbn; | |
120 | int error, maxrun, num; | |
121 | #if REV_ENDIAN_FS | |
122 | int rev_endian=0; | |
123 | #endif /* REV_ENDIAN_FS */ | |
124 | ||
125 | ip = VTOI(vp); | |
126 | mp = vp->v_mount; | |
127 | ump = VFSTOUFS(mp); | |
128 | ||
129 | #if REV_ENDIAN_FS | |
130 | rev_endian=(mp->mnt_flag & MNT_REVEND); | |
131 | #endif /* REV_ENDIAN_FS */ | |
132 | ||
133 | #if DIAGNOSTIC | |
134 | if (ap != NULL && nump == NULL || ap == NULL && nump != NULL) | |
135 | panic("ufs_bmaparray: invalid arguments"); | |
136 | #endif | |
137 | ||
138 | if (runp) { | |
139 | /* | |
140 | * XXX | |
141 | * If MAXPHYSIO is the largest transfer the disks can handle, | |
142 | * we probably want maxrun to be 1 block less so that we | |
143 | * don't create a block larger than the device can handle. | |
144 | */ | |
145 | *runp = 0; | |
91447636 | 146 | maxrun = MAXPHYSIO / mp->mnt_vfsstat.f_iosize - 1; |
1c79356b A |
147 | } |
148 | ||
149 | xap = ap == NULL ? a : ap; | |
150 | if (!nump) | |
151 | nump = # | |
152 | if (error = ufs_getlbns(vp, bn, xap, nump)) | |
153 | return (error); | |
154 | ||
155 | num = *nump; | |
156 | if (num == 0) { | |
157 | *bnp = blkptrtodb(ump, ip->i_db[bn]); | |
158 | if (*bnp == 0) | |
159 | *bnp = -1; | |
160 | else if (runp) | |
161 | for (++bn; bn < NDADDR && *runp < maxrun && | |
162 | is_sequential(ump, ip->i_db[bn - 1], ip->i_db[bn]); | |
163 | ++bn, ++*runp); | |
164 | return (0); | |
165 | } | |
166 | ||
167 | ||
168 | /* Get disk address out of indirect block array */ | |
169 | daddr = ip->i_ib[xap->in_off]; | |
170 | ||
171 | devvp = VFSTOUFS(vp->v_mount)->um_devvp; | |
172 | for (bp = NULL, ++xap; --num; ++xap) { | |
91447636 A |
173 | ufs_daddr_t *dataptr; |
174 | int bop; | |
175 | ||
176 | if ((metalbn = xap->in_lbn) == bn) | |
177 | /* | |
178 | * found the indirect block we were | |
179 | * looking for... exit the loop | |
180 | */ | |
181 | break; | |
182 | ||
183 | if (daddr == 0) | |
184 | bop = BLK_ONLYVALID | BLK_META; | |
185 | else | |
186 | bop = BLK_META; | |
1c79356b | 187 | |
91447636 A |
188 | if (bp) |
189 | buf_brelse(bp); | |
190 | bp = buf_getblk(vp, (daddr64_t)((unsigned)metalbn), mp->mnt_vfsstat.f_iosize, 0, 0, bop); | |
191 | ||
192 | if (bp == 0) { | |
193 | /* | |
194 | * Exit the loop if there is no disk address assigned yet and | |
195 | * the indirect block isn't in the cache | |
196 | */ | |
1c79356b | 197 | break; |
91447636 | 198 | } |
1c79356b A |
199 | /* |
200 | * If we get here, we've either got the block in the cache | |
201 | * or we have a disk address for it, go fetch it. | |
202 | */ | |
1c79356b | 203 | xap->in_exists = 1; |
91447636 A |
204 | |
205 | if (buf_valid(bp)) { | |
206 | trace(TR_BREADHIT, pack(vp, mp->mnt_vfsstat.f_iosize), metalbn); | |
1c79356b | 207 | } |
1c79356b | 208 | else { |
91447636 A |
209 | trace(TR_BREADMISS, pack(vp, mp->mnt_vfsstat.f_iosize), metalbn); |
210 | buf_setblkno(bp, blkptrtodb(ump, (daddr64_t)((unsigned)daddr))); | |
211 | buf_setflags(bp, B_READ); | |
212 | VNOP_STRATEGY(bp); | |
1c79356b | 213 | current_proc()->p_stats->p_ru.ru_inblock++; /* XXX */ |
91447636 A |
214 | if (error = (int)buf_biowait(bp)) { |
215 | buf_brelse(bp); | |
1c79356b A |
216 | return (error); |
217 | } | |
218 | } | |
91447636 A |
219 | dataptr = (ufs_daddr_t *)buf_dataptr(bp); |
220 | daddr = dataptr[xap->in_off]; | |
1c79356b A |
221 | #if REV_ENDIAN_FS |
222 | if (rev_endian) | |
0c530ab8 | 223 | daddr = OSSwapInt32(daddr); |
1c79356b A |
224 | #endif /* REV_ENDIAN_FS */ |
225 | if (num == 1 && daddr && runp) { | |
226 | #if REV_ENDIAN_FS | |
227 | if (rev_endian) { | |
228 | for (bn = xap->in_off + 1; | |
229 | bn < MNINDIR(ump) && *runp < maxrun && | |
230 | is_sequential(ump, | |
0c530ab8 A |
231 | OSSwapInt32(dataptr[bn - 1]), |
232 | OSSwapInt32(dataptr[bn])); | |
1c79356b A |
233 | ++bn, ++*runp); |
234 | } else { | |
235 | #endif /* REV_ENDIAN_FS */ | |
236 | for (bn = xap->in_off + 1; | |
237 | bn < MNINDIR(ump) && *runp < maxrun && | |
238 | is_sequential(ump, | |
91447636 A |
239 | dataptr[bn - 1], |
240 | dataptr[bn]); | |
1c79356b A |
241 | ++bn, ++*runp); |
242 | #if REV_ENDIAN_FS | |
243 | } | |
244 | #endif /* REV_ENDIAN_FS */ | |
245 | } | |
246 | } | |
247 | if (bp) | |
91447636 | 248 | buf_brelse(bp); |
1c79356b A |
249 | |
250 | daddr = blkptrtodb(ump, daddr); | |
251 | *bnp = daddr == 0 ? -1 : daddr; | |
252 | return (0); | |
253 | } | |
254 | ||
255 | /* | |
256 | * Create an array of logical block number/offset pairs which represent the | |
257 | * path of indirect blocks required to access a data block. The first "pair" | |
258 | * contains the logical block number of the appropriate single, double or | |
259 | * triple indirect block and the offset into the inode indirect block array. | |
260 | * Note, the logical block number of the inode single/double/triple indirect | |
261 | * block appears twice in the array, once with the offset into the i_ib and | |
262 | * once with the offset into the page itself. | |
263 | */ | |
264 | int | |
265 | ufs_getlbns(vp, bn, ap, nump) | |
266 | struct vnode *vp; | |
267 | ufs_daddr_t bn; | |
268 | struct indir *ap; | |
269 | int *nump; | |
270 | { | |
271 | long metalbn, realbn; | |
272 | struct ufsmount *ump; | |
273 | int blockcnt, i, numlevels, off; | |
274 | ||
275 | ump = VFSTOUFS(vp->v_mount); | |
276 | if (nump) | |
277 | *nump = 0; | |
278 | numlevels = 0; | |
279 | realbn = bn; | |
280 | if ((long)bn < 0) | |
281 | bn = -(long)bn; | |
282 | ||
283 | /* The first NDADDR blocks are direct blocks. */ | |
284 | if (bn < NDADDR) | |
285 | return (0); | |
286 | ||
287 | /* | |
288 | * Determine the number of levels of indirection. After this loop | |
289 | * is done, blockcnt indicates the number of data blocks possible | |
290 | * at the given level of indirection, and NIADDR - i is the number | |
291 | * of levels of indirection needed to locate the requested block. | |
292 | */ | |
293 | for (blockcnt = 1, i = NIADDR, bn -= NDADDR;; i--, bn -= blockcnt) { | |
294 | if (i == 0) | |
295 | return (EFBIG); | |
296 | blockcnt *= MNINDIR(ump); | |
297 | if (bn < blockcnt) | |
298 | break; | |
299 | } | |
300 | ||
301 | /* Calculate the address of the first meta-block. */ | |
302 | if (realbn >= 0) | |
303 | metalbn = -(realbn - bn + NIADDR - i); | |
304 | else | |
305 | metalbn = -(-realbn - bn + NIADDR - i); | |
306 | ||
307 | /* | |
308 | * At each iteration, off is the offset into the bap array which is | |
309 | * an array of disk addresses at the current level of indirection. | |
310 | * The logical block number and the offset in that block are stored | |
311 | * into the argument array. | |
312 | */ | |
313 | ap->in_lbn = metalbn; | |
314 | ap->in_off = off = NIADDR - i; | |
315 | ap->in_exists = 0; | |
316 | ap++; | |
317 | for (++numlevels; i <= NIADDR; i++) { | |
318 | /* If searching for a meta-data block, quit when found. */ | |
319 | if (metalbn == realbn) | |
320 | break; | |
321 | ||
322 | blockcnt /= MNINDIR(ump); | |
323 | off = (bn / blockcnt) % MNINDIR(ump); | |
324 | ||
325 | ++numlevels; | |
326 | ap->in_lbn = metalbn; | |
327 | ap->in_off = off; | |
328 | ap->in_exists = 0; | |
329 | ++ap; | |
330 | ||
331 | metalbn -= -1 + off * blockcnt; | |
332 | } | |
333 | if (nump) | |
334 | *nump = numlevels; | |
335 | return (0); | |
336 | } | |
337 | /* | |
91447636 A |
338 | * blockmap converts a file offsetto its physical block |
339 | * number on the disk... it optionally returns the physically | |
340 | * contiguous size. | |
1c79356b A |
341 | */ |
342 | int | |
91447636 A |
343 | ufs_blockmap(ap) |
344 | struct vnop_blockmap_args /* { | |
1c79356b A |
345 | struct vnode *a_vp; |
346 | off_t a_foffset; | |
347 | size_t a_size; | |
91447636 | 348 | daddr64_t *a_bpn; |
1c79356b A |
349 | size_t *a_run; |
350 | void *a_poff; | |
91447636 | 351 | int a_flags; |
1c79356b A |
352 | } */ *ap; |
353 | { | |
91447636 A |
354 | vnode_t vp = ap->a_vp; |
355 | daddr64_t * bnp = ap->a_bpn; | |
356 | size_t * runp = ap->a_run; | |
357 | int size = ap->a_size; | |
358 | struct fs * fs; | |
359 | struct inode *ip; | |
360 | ufs_daddr_t lbn; | |
1c79356b | 361 | ufs_daddr_t daddr = 0; |
91447636 A |
362 | int devBlockSize = 0; |
363 | int retsize = 0; | |
364 | int error = 0; | |
365 | int nblks; | |
1c79356b A |
366 | |
367 | ip = VTOI(vp); | |
368 | fs = ip->i_fs; | |
369 | ||
91447636 A |
370 | lbn = (ufs_daddr_t)lblkno(fs, ap->a_foffset); |
371 | devBlockSize = vfs_devblocksize(vnode_mount(vp)); | |
1c79356b | 372 | |
91447636 A |
373 | if (blkoff(fs, ap->a_foffset)) |
374 | panic("ufs_blockmap; allocation requested inside a block"); | |
1c79356b | 375 | |
91447636 A |
376 | if (size % devBlockSize) |
377 | panic("ufs_blockmap: size is not multiple of device block size\n"); | |
1c79356b | 378 | |
91447636 A |
379 | if ((error = ufs_bmaparray(vp, lbn, &daddr, NULL, NULL, &nblks))) |
380 | return (error); | |
1c79356b A |
381 | |
382 | if (bnp) | |
91447636 | 383 | *bnp = (daddr64_t)daddr; |
1c79356b A |
384 | |
385 | if (ap->a_poff) | |
386 | *(int *)ap->a_poff = 0; | |
387 | ||
1c79356b | 388 | if (runp) { |
91447636 A |
389 | if (lbn < 0) { |
390 | /* | |
391 | * we're dealing with the indirect blocks | |
392 | * which are always fs_bsize in size | |
393 | */ | |
394 | retsize = (nblks + 1) * fs->fs_bsize; | |
395 | } else if (daddr == -1 || nblks == 0) { | |
396 | /* | |
397 | * we're dealing with a 'hole'... UFS doesn't | |
398 | * have a clean way to determine it's size | |
399 | * or | |
400 | * there's are no physically contiguous blocks | |
401 | * so | |
402 | * just return the size of the lbn we started with | |
403 | */ | |
404 | retsize = blksize(fs, ip, lbn); | |
1c79356b | 405 | } else { |
91447636 A |
406 | /* |
407 | * we have 1 or more blocks that are physically contiguous | |
408 | * to our starting block number... the orignal block + (nblks - 1) | |
409 | * blocks must be full sized since only the last block can be | |
410 | * composed of fragments... | |
411 | */ | |
412 | retsize = nblks * fs->fs_bsize; | |
413 | ||
414 | /* | |
415 | * now compute the size of the last block and add it in | |
416 | */ | |
417 | retsize += blksize(fs, ip, (lbn + nblks)); | |
1c79356b | 418 | } |
91447636 A |
419 | if (retsize < size) |
420 | *runp = retsize; | |
421 | else | |
422 | *runp = size; | |
1c79356b | 423 | } |
1c79356b A |
424 | return (0); |
425 | } |