* Copyright (c) 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
* @(#)ufs_bmap.c 8.1 (Berkeley) %G%
#include <sys/resourcevar.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
* Bmap converts a the logical block number of a file to its physical block
* number on the disk. The conversion is done by using the logical block
* number to index into the array of block pointers described by the dinode.
struct vop_bmap_args
/* {
* Check for underlying vnode requests and ensure that logical
* to physical mapping is requested.
*ap
->a_vpp
= VTOI(ap
->a_vp
)->i_devvp
;
return (ufs_bmaparray(ap
->a_vp
, ap
->a_bn
, ap
->a_bnp
, NULL
, NULL
,
* Indirect blocks are now on the vnode for the file. They are given negative
* logical block numbers. Indirect blocks are addressed by the negative
* address of the first data block to which they point. Double indirect blocks
* are addressed by one less than the address of the first indirect block to
* which they point. Triple indirect blocks are addressed by one less than
* the address of the first double indirect block to which they point.
* ufs_bmaparray does the bmap conversion, and if requested returns the
* array of logical blocks which must be traversed to get to a block.
* Each entry contains the offset into that block that gets you to the
* next block and the disk address of the block (if it is assigned).
ufs_bmaparray(vp
, bn
, bnp
, ap
, nump
, runp
)
register struct inode
*ip
;
struct indir a
[NIADDR
], *xap
;
int bb
, error
, maxrun
, num
, off
;
struct vop_strategy_args vop_strategy_a
;
if (ap
!= NULL
&& nump
== NULL
|| ap
== NULL
&& nump
!= NULL
)
panic("ufs_bmaparray: invalid arguments");
* XXX If MAXBSIZE is the largest transfer the disks can
* handle, we probably want maxrun to be 1 block less so
* that we don't create a block larger than the device
maxrun
= MAXBSIZE
/ mp
->mnt_stat
.f_iosize
- 1;
xap
= ap
== NULL
? a
: ap
;
if (error
= ufs_getlbns(vp
, bn
, xap
, nump
))
*bnp
= blkptrtodb(ump
, ip
->i_db
[bn
]);
for (++bn
; bn
< NDADDR
&& *runp
< maxrun
&&
is_sequential(ump
, ip
->i_db
[bn
- 1], ip
->i_db
[bn
]);
/* Get disk address out of indirect block array */
daddr
= ip
->i_ib
[xap
->in_off
];
/* Fetch through the indirect blocks. */
devvp
= VFSTOUFS(vp
->v_mount
)->um_devvp
;
for (bp
= NULL
, ++xap
; --num
; ++xap
) {
* Exit the loop if there is no disk address assigned yet and
* the indirect block isn't in the cache, or if we were
* looking for an indirect block and we've found it.
if (daddr
== 0 && !incore(vp
, metalbn
) || metalbn
== bn
)
* If we get here, we've either got the block in the cache
* or we have a disk address for it, go fetch it.
bp
= getblk(vp
, metalbn
, mp
->mnt_stat
.f_iosize
, 0, 0);
if (bp
->b_flags
& (B_DONE
| B_DELWRI
)) {
trace(TR_BREADHIT
, pack(vp
, size
), metalbn
);
panic("ufs_bmaparry: indirect block not in cache");
trace(TR_BREADMISS
, pack(vp
, size
), metalbn
);
bp
->b_blkno
= blkptrtodb(ump
, daddr
);
curproc
->p_stats
->p_ru
.ru_inblock
++; /* XXX */
if (error
= biowait(bp
)) {
daddr
= bp
->b_un
.b_daddr
[xap
->in_off
];
if (num
== 1 && daddr
&& runp
)
for (bn
= xap
->in_off
+ 1;
bn
< MNINDIR(ump
) && *runp
< maxrun
&&
is_sequential(ump
, bp
->b_un
.b_daddr
[bn
- 1],
daddr
= blkptrtodb(ump
, daddr
);
*bnp
= daddr
== 0 ? -1 : daddr
;
* Create an array of logical block number/offset pairs which represent the
* path of indirect blocks required to access a data block. The first "pair"
* contains the logical block number of the appropriate single, double or
* triple indirect block and the offset into the inode indirect block array.
* Note, the logical block number of the inode single/double/triple indirect
* block appears twice in the array, once with the offset into the i_ib and
* once with the offset into the page itself.
ufs_getlbns(vp
, bn
, ap
, nump
)
int j
, numlevels
, off
, sh
;
ump
= VFSTOUFS(vp
->v_mount
);
/* The first NDADDR blocks are direct blocks. */
* Determine the number of levels of indirection. After this loop
* is done, sh indicates the number of data blocks possible at the
* given level of indirection, and NIADDR - j is the number of levels
* of indirection needed to locate the requested block.
for (j
= NIADDR
; j
> 0; j
--) {
/* Calculate the address of the first meta-block. */
metalbn
= -(realbn
- bn
+ NIADDR
- j
);
metalbn
= -(-realbn
- bn
+ NIADDR
- j
);
* At each iteration, off is the offset into the bap array which is
* an array of disk addresses at the current level of indirection.
* The logical block number and the offset in that block are stored
* into the argument array.
ap
->in_off
= off
= NIADDR
- j
;
for (; j
<= NIADDR
; j
++) {
/* If searching for a meta-data block, quit when found. */
off
= (bn
/ sh
) % MNINDIR(ump
);
metalbn
-= -1 + off
* sh
;