]>
git.saurik.com Git - apple/xnu.git/blob - bsd/ufs/ufs/ufs_bmap.c
86cf8a596a8ad88c8cf2eea4ff6a3c769ec8d99b
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>
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 */
89 * Bmap converts a the logical block number of a file to its physical block
90 * number on the disk. The conversion is done by using the logical block
91 * number to index into the array of block pointers described by the dinode.
95 struct vop_bmap_args
/* {
104 * Check for underlying vnode requests and ensure that logical
105 * to physical mapping is requested.
107 if (ap
->a_vpp
!= NULL
)
108 *ap
->a_vpp
= VTOI(ap
->a_vp
)->i_devvp
;
109 if (ap
->a_bnp
== NULL
)
112 return (ufs_bmaparray(ap
->a_vp
, ap
->a_bn
, ap
->a_bnp
, NULL
, NULL
,
117 * Indirect blocks are now on the vnode for the file. They are given negative
118 * logical block numbers. Indirect blocks are addressed by the negative
119 * address of the first data block to which they point. Double indirect blocks
120 * are addressed by one less than the address of the first indirect block to
121 * which they point. Triple indirect blocks are addressed by one less than
122 * the address of the first double indirect block to which they point.
124 * ufs_bmaparray does the bmap conversion, and if requested returns the
125 * array of logical blocks which must be traversed to get to a block.
126 * Each entry contains the offset into that block that gets you to the
127 * next block and the disk address of the block (if it is assigned).
131 ufs_bmaparray(vp
, bn
, bnp
, ap
, nump
, runp
)
139 register struct inode
*ip
;
141 struct ufsmount
*ump
;
144 struct indir a
[NIADDR
], *xap
;
147 int error
, maxrun
, num
;
150 #endif /* REV_ENDIAN_FS */
157 rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
158 #endif /* REV_ENDIAN_FS */
161 if (ap
!= NULL
&& nump
== NULL
|| ap
== NULL
&& nump
!= NULL
)
162 panic("ufs_bmaparray: invalid arguments");
168 * If MAXPHYSIO is the largest transfer the disks can handle,
169 * we probably want maxrun to be 1 block less so that we
170 * don't create a block larger than the device can handle.
173 maxrun
= MAXPHYSIO
/ mp
->mnt_stat
.f_iosize
- 1;
176 xap
= ap
== NULL
? a
: ap
;
179 if (error
= ufs_getlbns(vp
, bn
, xap
, nump
))
184 *bnp
= blkptrtodb(ump
, ip
->i_db
[bn
]);
188 for (++bn
; bn
< NDADDR
&& *runp
< maxrun
&&
189 is_sequential(ump
, ip
->i_db
[bn
- 1], ip
->i_db
[bn
]);
195 /* Get disk address out of indirect block array */
196 daddr
= ip
->i_ib
[xap
->in_off
];
198 devvp
= VFSTOUFS(vp
->v_mount
)->um_devvp
;
199 for (bp
= NULL
, ++xap
; --num
; ++xap
) {
201 * Exit the loop if there is no disk address assigned yet and
202 * the indirect block isn't in the cache, or if we were
203 * looking for an indirect block and we've found it.
206 metalbn
= xap
->in_lbn
;
207 if (daddr
== 0 && !incore(vp
, metalbn
) || metalbn
== bn
)
210 * If we get here, we've either got the block in the cache
211 * or we have a disk address for it, go fetch it.
217 bp
= getblk(vp
, metalbn
, mp
->mnt_stat
.f_iosize
, 0, 0, BLK_META
);
218 if (bp
->b_flags
& (B_DONE
| B_DELWRI
)) {
219 trace(TR_BREADHIT
, pack(vp
, mp
->mnt_stat
.f_iosize
), metalbn
);
223 panic("ufs_bmaparry: indirect block not in cache");
226 trace(TR_BREADMISS
, pack(vp
, mp
->mnt_stat
.f_iosize
), metalbn
);
227 bp
->b_blkno
= blkptrtodb(ump
, daddr
);
228 bp
->b_flags
|= B_READ
;
230 current_proc()->p_stats
->p_ru
.ru_inblock
++; /* XXX */
231 if (error
= biowait(bp
)) {
237 daddr
= ((ufs_daddr_t
*)bp
->b_data
)[xap
->in_off
];
240 daddr
= NXSwapLong(daddr
);
241 #endif /* REV_ENDIAN_FS */
242 if (num
== 1 && daddr
&& runp
) {
245 for (bn
= xap
->in_off
+ 1;
246 bn
< MNINDIR(ump
) && *runp
< maxrun
&&
248 NXSwapLong(((ufs_daddr_t
*)bp
->b_data
)[bn
- 1]),
249 NXSwapLong(((ufs_daddr_t
*)bp
->b_data
)[bn
]));
252 #endif /* REV_ENDIAN_FS */
253 for (bn
= xap
->in_off
+ 1;
254 bn
< MNINDIR(ump
) && *runp
< maxrun
&&
256 ((ufs_daddr_t
*)bp
->b_data
)[bn
- 1],
257 ((ufs_daddr_t
*)bp
->b_data
)[bn
]);
261 #endif /* REV_ENDIAN_FS */
267 daddr
= blkptrtodb(ump
, daddr
);
268 *bnp
= daddr
== 0 ? -1 : daddr
;
273 * Create an array of logical block number/offset pairs which represent the
274 * path of indirect blocks required to access a data block. The first "pair"
275 * contains the logical block number of the appropriate single, double or
276 * triple indirect block and the offset into the inode indirect block array.
277 * Note, the logical block number of the inode single/double/triple indirect
278 * block appears twice in the array, once with the offset into the i_ib and
279 * once with the offset into the page itself.
282 ufs_getlbns(vp
, bn
, ap
, nump
)
288 long metalbn
, realbn
;
289 struct ufsmount
*ump
;
290 int blockcnt
, i
, numlevels
, off
;
292 ump
= VFSTOUFS(vp
->v_mount
);
300 /* The first NDADDR blocks are direct blocks. */
305 * Determine the number of levels of indirection. After this loop
306 * is done, blockcnt indicates the number of data blocks possible
307 * at the given level of indirection, and NIADDR - i is the number
308 * of levels of indirection needed to locate the requested block.
310 for (blockcnt
= 1, i
= NIADDR
, bn
-= NDADDR
;; i
--, bn
-= blockcnt
) {
313 blockcnt
*= MNINDIR(ump
);
318 /* Calculate the address of the first meta-block. */
320 metalbn
= -(realbn
- bn
+ NIADDR
- i
);
322 metalbn
= -(-realbn
- bn
+ NIADDR
- i
);
325 * At each iteration, off is the offset into the bap array which is
326 * an array of disk addresses at the current level of indirection.
327 * The logical block number and the offset in that block are stored
328 * into the argument array.
330 ap
->in_lbn
= metalbn
;
331 ap
->in_off
= off
= NIADDR
- i
;
334 for (++numlevels
; i
<= NIADDR
; i
++) {
335 /* If searching for a meta-data block, quit when found. */
336 if (metalbn
== realbn
)
339 blockcnt
/= MNINDIR(ump
);
340 off
= (bn
/ blockcnt
) % MNINDIR(ump
);
343 ap
->in_lbn
= metalbn
;
348 metalbn
-= -1 + off
* blockcnt
;
355 * Cmap converts a the file offset of a file to its physical block
356 * number on the disk And returns contiguous size for transfer.
360 struct vop_cmap_args
/* {
369 struct vnode
* vp
= ap
->a_vp
;
370 ufs_daddr_t
*bnp
= ap
->a_bpn
;
371 size_t *runp
= ap
->a_run
;
372 int size
= ap
->a_size
;
375 register struct inode
*ip
;
376 ufs_daddr_t daddr
= 0;
386 if (blkoff(fs
, ap
->a_foffset
)) {
387 panic("ufs_cmap; allocation requested inside a block");
390 bn
= (daddr_t
)lblkno(fs
, ap
->a_foffset
);
391 VOP_DEVBLOCKSIZE(ip
->i_devvp
, &devBlockSize
);
393 if (size
% devBlockSize
) {
394 panic("ufs_cmap: size is not multiple of device block size\n");
397 if (error
= VOP_BMAP(vp
, bn
, (struct vnode
**) 0, &daddr
, &nblks
)) {
401 retsize
= nblks
* fs
->fs_bsize
;
407 *(int *)ap
->a_poff
= 0;
410 if (size
< fs
->fs_bsize
) {
411 retsize
= fragroundup(fs
, size
);
417 *runp
= fs
->fs_bsize
;
423 if ((size
< fs
->fs_bsize
)) {
428 retsize
+= fs
->fs_bsize
;
434 if (size
< fs
->fs_bsize
) {
435 retsize
= fragroundup(fs
, size
);
441 *runp
= fs
->fs_bsize
;
451 * Cmap converts a the file offset of a file to its physical block
452 * number on the disk And returns contiguous size for transfer.
456 struct vop_cmap_args
/* {
465 struct vnode
* vp
= ap
->a_vp
;
466 ufs_daddr_t
*bnp
= ap
->a_bpn
;
467 size_t *runp
= ap
->a_run
;
471 register struct inode
*ip
;
473 struct ufsmount
*ump
;
476 struct indir a
[NIADDR
], *xap
;
479 int error
, maxrun
, num
;
482 int size
= ap
->a_size
;
491 #endif /* REV_ENDIAN_FS */
499 VOP_DEVBLOCKSIZE(ip
->i_devvp
, &devBlockSize
);
500 bn
= (daddr_t
)lblkno(fs
, ap
->a_foffset
);
502 if (size
% devBlockSize
) {
503 panic("ufs_cmap: size is not multiple of device block size\n");
506 block_offset
= blkoff(fs
, ap
->a_foffset
);
508 panic("ufs_cmap; allocation requested inside a block");
512 VOP_OFFTOBLK(vp
, ap
->a_foffset
, & orig_blkno
);
514 /* less than block size and not block offset aligned */
515 if ( (size
< fs
->fs_bsize
) && fragoff(fs
, size
) && block_offset
) {
516 panic("ffs_cmap: size not a mult of fragment\n");
519 if (size
> fs
->fs_bsize
&& fragoff(fs
, size
)) {
520 panic("ffs_cmap: more than bsize & not a multiple of fragment\n");
524 rev_endian
=(mp
->mnt_flag
& MNT_REVEND
);
525 #endif /* REV_ENDIAN_FS */
530 if ( size
> MAXPHYSIO
)
532 nblks
= (blkroundup(fs
, size
))/fs
->fs_bsize
;
536 if (error
= ufs_getlbns(vp
, bn
, xap
, &num
))
541 daddr
= blkptrtodb(ump
, ip
->i_db
[bn
]);
542 *bnp
= ((daddr
== 0) ? -1 : daddr
);
544 for (++bn
; bn
< NDADDR
&& blks
< nblks
&&
546 is_sequential(ump
, ip
->i_db
[bn
- 1], ip
->i_db
[bn
]);
550 retsize
= lblktosize(fs
, blks
);
556 if (size
< fs
->fs_bsize
) {
557 retsize
= fragroundup(fs
, size
);
563 *runp
= fs
->fs_bsize
;
567 *(int *)ap
->a_poff
= 0;
570 if (VOP_BMAP(vp
, orig_blkno
, NULL
, &orig_bblkno
, NULL
)) {
571 panic("vop_bmap failed\n");
573 if(daddr
!= orig_bblkno
) {
574 panic("vop_bmap and vop_cmap differ\n");
581 /* Get disk address out of indirect block array */
582 daddr
= ip
->i_ib
[xap
->in_off
];
584 devvp
= VFSTOUFS(vp
->v_mount
)->um_devvp
;
585 for (bp
= NULL
, ++xap
; --num
; ++xap
) {
587 * Exit the loop if there is no disk address assigned yet
588 * or if we were looking for an indirect block and we've
592 metalbn
= xap
->in_lbn
;
593 if (daddr
== 0 || metalbn
== bn
)
596 * We have a disk address for it, go fetch it.
602 bp
= getblk(vp
, metalbn
, mp
->mnt_stat
.f_iosize
, 0, 0, BLK_META
);
603 if (bp
->b_flags
& (B_DONE
| B_DELWRI
)) {
604 trace(TR_BREADHIT
, pack(vp
, mp
->mnt_stat
.f_iosize
), metalbn
);
607 trace(TR_BREADMISS
, pack(vp
, mp
->mnt_stat
.f_iosize
), metalbn
);
608 bp
->b_blkno
= blkptrtodb(ump
, daddr
);
609 bp
->b_flags
|= B_READ
;
611 current_proc()->p_stats
->p_ru
.ru_inblock
++; /* XXX */
612 if (error
= biowait(bp
)) {
618 daddr
= ((ufs_daddr_t
*)bp
->b_data
)[xap
->in_off
];
621 daddr
= NXSwapLong(daddr
);
622 #endif /* REV_ENDIAN_FS */
623 if (num
== 1 && daddr
&& runp
) {
627 for (bn
= xap
->in_off
+ 1;
628 bn
< MNINDIR(ump
) && blks
< maxrun
&&
630 NXSwapLong(((ufs_daddr_t
*)bp
->b_data
)[bn
- 1]),
631 NXSwapLong(((ufs_daddr_t
*)bp
->b_data
)[bn
]));
634 #endif /* REV_ENDIAN_FS */
635 for (bn
= xap
->in_off
+ 1;
636 bn
< MNINDIR(ump
) && blks
< maxrun
&&
638 ((ufs_daddr_t
*)bp
->b_data
)[bn
- 1],
639 ((ufs_daddr_t
*)bp
->b_data
)[bn
]);
643 #endif /* REV_ENDIAN_FS */
649 daddr
= blkptrtodb(ump
, daddr
);
650 *bnp
= ((daddr
== 0) ? -1 : daddr
);
653 retsize
= lblktosize(fs
, blks
);
659 if (size
< fs
->fs_bsize
) {
660 retsize
= fragroundup(fs
, size
);
666 *runp
= fs
->fs_bsize
;
671 if (daddr
&& ap
->a_poff
)
672 *(int *)ap
->a_poff
= 0;
674 if (VOP_BMAP(vp
, orig_blkno
, (struct vnode
**) 0, &orig_bblkno
, 0)) {
675 panic("vop_bmap failed\n");
677 if(daddr
!= orig_bblkno
) {
678 panic("vop_bmap and vop_cmap differ\n");
683 #endif /* NOTTOBEUSED */