]>
git.saurik.com Git - apple/xnu.git/blob - bsd/ufs/ufs/ufs_bmap.c
ca7fd9352de5ec6574b48f062717b325d1fdd7d3
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
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.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
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.
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
60 * @(#)ufs_bmap.c 8.7 (Berkeley) 3/21/95
64 * 11-July-97 Umesh Vaishampayan (umeshv@apple.com)
65 * Cleanup. Fixed compilation error when tracing is turned on.
67 #include <rev_endian_fs.h>
68 #include <sys/param.h>
70 #include <sys/proc_internal.h> /* for p_stats */
71 #include <sys/vnode_internal.h>
72 #include <sys/mount_internal.h>
73 #include <sys/resourcevar.h>
74 #include <sys/trace.h>
75 #include <sys/quota.h>
77 #include <miscfs/specfs/specdev.h>
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>
84 #include <ufs/ufs/ufs_byte_order.h>
85 #include <architecture/byte_order.h>
86 #endif /* REV_ENDIAN_FS */
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.
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).
104 ufs_bmaparray(vp
, bn
, bnp
, ap
, nump
, runp
)
112 register struct inode
*ip
;
114 struct ufsmount
*ump
;
117 struct indir a
[NIADDR
], *xap
;
120 int error
, maxrun
, num
;
123 #endif /* REV_ENDIAN_FS */
130 rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
131 #endif /* REV_ENDIAN_FS */
134 if (ap
!= NULL
&& nump
== NULL
|| ap
== NULL
&& nump
!= NULL
)
135 panic("ufs_bmaparray: invalid arguments");
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.
146 maxrun
= MAXPHYSIO
/ mp
->mnt_vfsstat
.f_iosize
- 1;
149 xap
= ap
== NULL
? a
: ap
;
152 if (error
= ufs_getlbns(vp
, bn
, xap
, nump
))
157 *bnp
= blkptrtodb(ump
, ip
->i_db
[bn
]);
161 for (++bn
; bn
< NDADDR
&& *runp
< maxrun
&&
162 is_sequential(ump
, ip
->i_db
[bn
- 1], ip
->i_db
[bn
]);
168 /* Get disk address out of indirect block array */
169 daddr
= ip
->i_ib
[xap
->in_off
];
171 devvp
= VFSTOUFS(vp
->v_mount
)->um_devvp
;
172 for (bp
= NULL
, ++xap
; --num
; ++xap
) {
173 ufs_daddr_t
*dataptr
;
176 if ((metalbn
= xap
->in_lbn
) == bn
)
178 * found the indirect block we were
179 * looking for... exit the loop
184 bop
= BLK_ONLYVALID
| BLK_META
;
190 bp
= buf_getblk(vp
, (daddr64_t
)((unsigned)metalbn
), mp
->mnt_vfsstat
.f_iosize
, 0, 0, bop
);
194 * Exit the loop if there is no disk address assigned yet and
195 * the indirect block isn't in the cache
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.
206 trace(TR_BREADHIT
, pack(vp
, mp
->mnt_vfsstat
.f_iosize
), metalbn
);
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
);
213 current_proc()->p_stats
->p_ru
.ru_inblock
++; /* XXX */
214 if (error
= (int)buf_biowait(bp
)) {
219 dataptr
= (ufs_daddr_t
*)buf_dataptr(bp
);
220 daddr
= dataptr
[xap
->in_off
];
223 daddr
= NXSwapLong(daddr
);
224 #endif /* REV_ENDIAN_FS */
225 if (num
== 1 && daddr
&& runp
) {
228 for (bn
= xap
->in_off
+ 1;
229 bn
< MNINDIR(ump
) && *runp
< maxrun
&&
231 NXSwapLong(dataptr
[bn
- 1]),
232 NXSwapLong(dataptr
[bn
]));
235 #endif /* REV_ENDIAN_FS */
236 for (bn
= xap
->in_off
+ 1;
237 bn
< MNINDIR(ump
) && *runp
< maxrun
&&
244 #endif /* REV_ENDIAN_FS */
250 daddr
= blkptrtodb(ump
, daddr
);
251 *bnp
= daddr
== 0 ? -1 : daddr
;
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.
265 ufs_getlbns(vp
, bn
, ap
, nump
)
271 long metalbn
, realbn
;
272 struct ufsmount
*ump
;
273 int blockcnt
, i
, numlevels
, off
;
275 ump
= VFSTOUFS(vp
->v_mount
);
283 /* The first NDADDR blocks are direct blocks. */
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.
293 for (blockcnt
= 1, i
= NIADDR
, bn
-= NDADDR
;; i
--, bn
-= blockcnt
) {
296 blockcnt
*= MNINDIR(ump
);
301 /* Calculate the address of the first meta-block. */
303 metalbn
= -(realbn
- bn
+ NIADDR
- i
);
305 metalbn
= -(-realbn
- bn
+ NIADDR
- i
);
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.
313 ap
->in_lbn
= metalbn
;
314 ap
->in_off
= off
= NIADDR
- i
;
317 for (++numlevels
; i
<= NIADDR
; i
++) {
318 /* If searching for a meta-data block, quit when found. */
319 if (metalbn
== realbn
)
322 blockcnt
/= MNINDIR(ump
);
323 off
= (bn
/ blockcnt
) % MNINDIR(ump
);
326 ap
->in_lbn
= metalbn
;
331 metalbn
-= -1 + off
* blockcnt
;
338 * blockmap converts a file offsetto its physical block
339 * number on the disk... it optionally returns the physically
344 struct vnop_blockmap_args
/* {
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
;
361 ufs_daddr_t daddr
= 0;
362 int devBlockSize
= 0;
370 lbn
= (ufs_daddr_t
)lblkno(fs
, ap
->a_foffset
);
371 devBlockSize
= vfs_devblocksize(vnode_mount(vp
));
373 if (blkoff(fs
, ap
->a_foffset
))
374 panic("ufs_blockmap; allocation requested inside a block");
376 if (size
% devBlockSize
)
377 panic("ufs_blockmap: size is not multiple of device block size\n");
379 if ((error
= ufs_bmaparray(vp
, lbn
, &daddr
, NULL
, NULL
, &nblks
)))
383 *bnp
= (daddr64_t
)daddr
;
386 *(int *)ap
->a_poff
= 0;
391 * we're dealing with the indirect blocks
392 * which are always fs_bsize in size
394 retsize
= (nblks
+ 1) * fs
->fs_bsize
;
395 } else if (daddr
== -1 || nblks
== 0) {
397 * we're dealing with a 'hole'... UFS doesn't
398 * have a clean way to determine it's size
400 * there's are no physically contiguous blocks
402 * just return the size of the lbn we started with
404 retsize
= blksize(fs
, ip
, lbn
);
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...
412 retsize
= nblks
* fs
->fs_bsize
;
415 * now compute the size of the last block and add it in
417 retsize
+= blksize(fs
, ip
, (lbn
+ nblks
));