]>
git.saurik.com Git - apple/xnu.git/blob - bsd/ufs/ufs/ufs_bmap.c
4acc2dd91a46d2d2412df7d76df828cfb447f833
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>
71 #include <sys/vnode.h>
72 #include <sys/mount.h>
73 #include <sys/resourcevar.h>
74 #include <sys/trace.h>
76 #include <miscfs/specfs/specdev.h>
78 #include <ufs/ufs/quota.h>
79 #include <ufs/ufs/inode.h>
80 #include <ufs/ufs/ufsmount.h>
81 #include <ufs/ufs/ufs_extern.h>
83 #include <ufs/ufs/ufs_byte_order.h>
84 #include <architecture/byte_order.h>
85 #endif /* REV_ENDIAN_FS */
88 * Bmap converts a the logical block number of a file to its physical block
89 * number on the disk. The conversion is done by using the logical block
90 * number to index into the array of block pointers described by the dinode.
94 struct vop_bmap_args
/* {
103 * Check for underlying vnode requests and ensure that logical
104 * to physical mapping is requested.
106 if (ap
->a_vpp
!= NULL
)
107 *ap
->a_vpp
= VTOI(ap
->a_vp
)->i_devvp
;
108 if (ap
->a_bnp
== NULL
)
111 return (ufs_bmaparray(ap
->a_vp
, ap
->a_bn
, ap
->a_bnp
, NULL
, NULL
,
116 * Indirect blocks are now on the vnode for the file. They are given negative
117 * logical block numbers. Indirect blocks are addressed by the negative
118 * address of the first data block to which they point. Double indirect blocks
119 * are addressed by one less than the address of the first indirect block to
120 * which they point. Triple indirect blocks are addressed by one less than
121 * the address of the first double indirect block to which they point.
123 * ufs_bmaparray does the bmap conversion, and if requested returns the
124 * array of logical blocks which must be traversed to get to a block.
125 * Each entry contains the offset into that block that gets you to the
126 * next block and the disk address of the block (if it is assigned).
130 ufs_bmaparray(vp
, bn
, bnp
, ap
, nump
, runp
)
138 register struct inode
*ip
;
140 struct ufsmount
*ump
;
143 struct indir a
[NIADDR
], *xap
;
146 int error
, maxrun
, num
;
149 #endif /* REV_ENDIAN_FS */
156 rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
157 #endif /* REV_ENDIAN_FS */
160 if (ap
!= NULL
&& nump
== NULL
|| ap
== NULL
&& nump
!= NULL
)
161 panic("ufs_bmaparray: invalid arguments");
167 * If MAXPHYSIO is the largest transfer the disks can handle,
168 * we probably want maxrun to be 1 block less so that we
169 * don't create a block larger than the device can handle.
172 maxrun
= MAXPHYSIO
/ mp
->mnt_stat
.f_iosize
- 1;
175 xap
= ap
== NULL
? a
: ap
;
178 if (error
= ufs_getlbns(vp
, bn
, xap
, nump
))
183 *bnp
= blkptrtodb(ump
, ip
->i_db
[bn
]);
187 for (++bn
; bn
< NDADDR
&& *runp
< maxrun
&&
188 is_sequential(ump
, ip
->i_db
[bn
- 1], ip
->i_db
[bn
]);
194 /* Get disk address out of indirect block array */
195 daddr
= ip
->i_ib
[xap
->in_off
];
197 devvp
= VFSTOUFS(vp
->v_mount
)->um_devvp
;
198 for (bp
= NULL
, ++xap
; --num
; ++xap
) {
200 * Exit the loop if there is no disk address assigned yet and
201 * the indirect block isn't in the cache, or if we were
202 * looking for an indirect block and we've found it.
205 metalbn
= xap
->in_lbn
;
206 if (daddr
== 0 && !incore(vp
, metalbn
) || metalbn
== bn
)
209 * If we get here, we've either got the block in the cache
210 * or we have a disk address for it, go fetch it.
216 bp
= getblk(vp
, metalbn
, mp
->mnt_stat
.f_iosize
, 0, 0, BLK_META
);
217 if (bp
->b_flags
& (B_DONE
| B_DELWRI
)) {
218 trace(TR_BREADHIT
, pack(vp
, mp
->mnt_stat
.f_iosize
), metalbn
);
222 panic("ufs_bmaparry: indirect block not in cache");
225 trace(TR_BREADMISS
, pack(vp
, mp
->mnt_stat
.f_iosize
), metalbn
);
226 bp
->b_blkno
= blkptrtodb(ump
, daddr
);
227 bp
->b_flags
|= B_READ
;
229 current_proc()->p_stats
->p_ru
.ru_inblock
++; /* XXX */
230 if (error
= biowait(bp
)) {
236 daddr
= ((ufs_daddr_t
*)bp
->b_data
)[xap
->in_off
];
239 daddr
= NXSwapLong(daddr
);
240 #endif /* REV_ENDIAN_FS */
241 if (num
== 1 && daddr
&& runp
) {
244 for (bn
= xap
->in_off
+ 1;
245 bn
< MNINDIR(ump
) && *runp
< maxrun
&&
247 NXSwapLong(((ufs_daddr_t
*)bp
->b_data
)[bn
- 1]),
248 NXSwapLong(((ufs_daddr_t
*)bp
->b_data
)[bn
]));
251 #endif /* REV_ENDIAN_FS */
252 for (bn
= xap
->in_off
+ 1;
253 bn
< MNINDIR(ump
) && *runp
< maxrun
&&
255 ((ufs_daddr_t
*)bp
->b_data
)[bn
- 1],
256 ((ufs_daddr_t
*)bp
->b_data
)[bn
]);
260 #endif /* REV_ENDIAN_FS */
266 daddr
= blkptrtodb(ump
, daddr
);
267 *bnp
= daddr
== 0 ? -1 : daddr
;
272 * Create an array of logical block number/offset pairs which represent the
273 * path of indirect blocks required to access a data block. The first "pair"
274 * contains the logical block number of the appropriate single, double or
275 * triple indirect block and the offset into the inode indirect block array.
276 * Note, the logical block number of the inode single/double/triple indirect
277 * block appears twice in the array, once with the offset into the i_ib and
278 * once with the offset into the page itself.
281 ufs_getlbns(vp
, bn
, ap
, nump
)
287 long metalbn
, realbn
;
288 struct ufsmount
*ump
;
289 int blockcnt
, i
, numlevels
, off
;
291 ump
= VFSTOUFS(vp
->v_mount
);
299 /* The first NDADDR blocks are direct blocks. */
304 * Determine the number of levels of indirection. After this loop
305 * is done, blockcnt indicates the number of data blocks possible
306 * at the given level of indirection, and NIADDR - i is the number
307 * of levels of indirection needed to locate the requested block.
309 for (blockcnt
= 1, i
= NIADDR
, bn
-= NDADDR
;; i
--, bn
-= blockcnt
) {
312 blockcnt
*= MNINDIR(ump
);
317 /* Calculate the address of the first meta-block. */
319 metalbn
= -(realbn
- bn
+ NIADDR
- i
);
321 metalbn
= -(-realbn
- bn
+ NIADDR
- i
);
324 * At each iteration, off is the offset into the bap array which is
325 * an array of disk addresses at the current level of indirection.
326 * The logical block number and the offset in that block are stored
327 * into the argument array.
329 ap
->in_lbn
= metalbn
;
330 ap
->in_off
= off
= NIADDR
- i
;
333 for (++numlevels
; i
<= NIADDR
; i
++) {
334 /* If searching for a meta-data block, quit when found. */
335 if (metalbn
== realbn
)
338 blockcnt
/= MNINDIR(ump
);
339 off
= (bn
/ blockcnt
) % MNINDIR(ump
);
342 ap
->in_lbn
= metalbn
;
347 metalbn
-= -1 + off
* blockcnt
;
354 * Cmap converts a the file offset of a file to its physical block
355 * number on the disk And returns contiguous size for transfer.
359 struct vop_cmap_args
/* {
368 struct vnode
* vp
= ap
->a_vp
;
369 ufs_daddr_t
*bnp
= ap
->a_bpn
;
370 size_t *runp
= ap
->a_run
;
371 int size
= ap
->a_size
;
374 register struct inode
*ip
;
375 ufs_daddr_t daddr
= 0;
385 if (blkoff(fs
, ap
->a_foffset
)) {
386 panic("ufs_cmap; allocation requested inside a block");
389 bn
= (daddr_t
)lblkno(fs
, ap
->a_foffset
);
390 VOP_DEVBLOCKSIZE(ip
->i_devvp
, &devBlockSize
);
392 if (size
% devBlockSize
) {
393 panic("ufs_cmap: size is not multiple of device block size\n");
396 if (error
= VOP_BMAP(vp
, bn
, (struct vnode
**) 0, &daddr
, &nblks
)) {
400 retsize
= nblks
* fs
->fs_bsize
;
406 *(int *)ap
->a_poff
= 0;
409 if (size
< fs
->fs_bsize
) {
410 retsize
= fragroundup(fs
, size
);
416 *runp
= fs
->fs_bsize
;
422 if ((size
< fs
->fs_bsize
)) {
427 retsize
+= fs
->fs_bsize
;
433 if (size
< fs
->fs_bsize
) {
434 retsize
= fragroundup(fs
, size
);
440 *runp
= fs
->fs_bsize
;
450 * Cmap converts a the file offset of a file to its physical block
451 * number on the disk And returns contiguous size for transfer.
455 struct vop_cmap_args
/* {
464 struct vnode
* vp
= ap
->a_vp
;
465 ufs_daddr_t
*bnp
= ap
->a_bpn
;
466 size_t *runp
= ap
->a_run
;
470 register struct inode
*ip
;
472 struct ufsmount
*ump
;
475 struct indir a
[NIADDR
], *xap
;
478 int error
, maxrun
, num
;
481 int size
= ap
->a_size
;
490 #endif /* REV_ENDIAN_FS */
498 VOP_DEVBLOCKSIZE(ip
->i_devvp
, &devBlockSize
);
499 bn
= (daddr_t
)lblkno(fs
, ap
->a_foffset
);
501 if (size
% devBlockSize
) {
502 panic("ufs_cmap: size is not multiple of device block size\n");
505 block_offset
= blkoff(fs
, ap
->a_foffset
);
507 panic("ufs_cmap; allocation requested inside a block");
511 VOP_OFFTOBLK(vp
, ap
->a_foffset
, & orig_blkno
);
513 /* less than block size and not block offset aligned */
514 if ( (size
< fs
->fs_bsize
) && fragoff(fs
, size
) && block_offset
) {
515 panic("ffs_cmap: size not a mult of fragment\n");
518 if (size
> fs
->fs_bsize
&& fragoff(fs
, size
)) {
519 panic("ffs_cmap: more than bsize & not a multiple of fragment\n");
523 rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
524 #endif /* REV_ENDIAN_FS */
529 if ( size
> MAXPHYSIO
)
531 nblks
= (blkroundup(fs
, size
))/fs
->fs_bsize
;
535 if (error
= ufs_getlbns(vp
, bn
, xap
, &num
))
540 daddr
= blkptrtodb(ump
, ip
->i_db
[bn
]);
541 *bnp
= ((daddr
== 0) ? -1 : daddr
);
543 for (++bn
; bn
< NDADDR
&& blks
< nblks
&&
545 is_sequential(ump
, ip
->i_db
[bn
- 1], ip
->i_db
[bn
]);
549 retsize
= lblktosize(fs
, blks
);
555 if (size
< fs
->fs_bsize
) {
556 retsize
= fragroundup(fs
, size
);
562 *runp
= fs
->fs_bsize
;
566 *(int *)ap
->a_poff
= 0;
569 if (VOP_BMAP(vp
, orig_blkno
, NULL
, &orig_bblkno
, NULL
)) {
570 panic("vop_bmap failed\n");
572 if(daddr
!= orig_bblkno
) {
573 panic("vop_bmap and vop_cmap differ\n");
580 /* Get disk address out of indirect block array */
581 daddr
= ip
->i_ib
[xap
->in_off
];
583 devvp
= VFSTOUFS(vp
->v_mount
)->um_devvp
;
584 for (bp
= NULL
, ++xap
; --num
; ++xap
) {
586 * Exit the loop if there is no disk address assigned yet
587 * or if we were looking for an indirect block and we've
591 metalbn
= xap
->in_lbn
;
592 if (daddr
== 0 || metalbn
== bn
)
595 * We have a disk address for it, go fetch it.
601 bp
= getblk(vp
, metalbn
, mp
->mnt_stat
.f_iosize
, 0, 0, BLK_META
);
602 if (bp
->b_flags
& (B_DONE
| B_DELWRI
)) {
603 trace(TR_BREADHIT
, pack(vp
, mp
->mnt_stat
.f_iosize
), metalbn
);
606 trace(TR_BREADMISS
, pack(vp
, mp
->mnt_stat
.f_iosize
), metalbn
);
607 bp
->b_blkno
= blkptrtodb(ump
, daddr
);
608 bp
->b_flags
|= B_READ
;
610 current_proc()->p_stats
->p_ru
.ru_inblock
++; /* XXX */
611 if (error
= biowait(bp
)) {
617 daddr
= ((ufs_daddr_t
*)bp
->b_data
)[xap
->in_off
];
620 daddr
= NXSwapLong(daddr
);
621 #endif /* REV_ENDIAN_FS */
622 if (num
== 1 && daddr
&& runp
) {
626 for (bn
= xap
->in_off
+ 1;
627 bn
< MNINDIR(ump
) && blks
< maxrun
&&
629 NXSwapLong(((ufs_daddr_t
*)bp
->b_data
)[bn
- 1]),
630 NXSwapLong(((ufs_daddr_t
*)bp
->b_data
)[bn
]));
633 #endif /* REV_ENDIAN_FS */
634 for (bn
= xap
->in_off
+ 1;
635 bn
< MNINDIR(ump
) && blks
< maxrun
&&
637 ((ufs_daddr_t
*)bp
->b_data
)[bn
- 1],
638 ((ufs_daddr_t
*)bp
->b_data
)[bn
]);
642 #endif /* REV_ENDIAN_FS */
648 daddr
= blkptrtodb(ump
, daddr
);
649 *bnp
= ((daddr
== 0) ? -1 : daddr
);
652 retsize
= lblktosize(fs
, blks
);
658 if (size
< fs
->fs_bsize
) {
659 retsize
= fragroundup(fs
, size
);
665 *runp
= fs
->fs_bsize
;
670 if (daddr
&& ap
->a_poff
)
671 *(int *)ap
->a_poff
= 0;
673 if (VOP_BMAP(vp
, orig_blkno
, (struct vnode
**) 0, &orig_bblkno
, 0)) {
674 panic("vop_bmap failed\n");
676 if(daddr
!= orig_bblkno
) {
677 panic("vop_bmap and vop_cmap differ\n");
682 #endif /* NOTTOBEUSED */