* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)ffs_balloc.c 7.17 (Berkeley) %G%
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ffs/ffs_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.
ffs_bmap(vp
, bn
, vpp
, bnp
)
register struct inode
*ip
;
* Check for underlying vnode requests and ensure that logical
* to physical mapping is requested.
* The first NDADDR blocks are direct blocks
* Determine the number of levels of indirection.
for (j
= NIADDR
; j
> 0; j
--) {
* Fetch through the indirect blocks.
nb
= ip
->i_ib
[NIADDR
- j
];
for (; j
<= NIADDR
; j
++) {
if (error
= bread(ip
->i_devvp
, fsbtodb(fs
, nb
),
(int)fs
->fs_bsize
, NOCRED
, &bp
)) {
i
= (bn
/ sh
) % NINDIR(fs
);
* Balloc defines the structure of file system storage
* by allocating the physical blocks on a device given
* the inode and the logical block number in a file.
ffs_balloc(ip
, bn
, size
, cred
, bpp
, flags
)
register struct inode
*ip
;
struct vnode
*vp
= ITOV(ip
);
int osize
, nsize
, i
, j
, sh
, error
;
daddr_t newb
, lbn
, *bap
, pref
;
* If the next write will extend the file into a new block,
* and the file is currently composed of a fragment
* this fragment has to be extended to be a full block.
nb
= lblkno(fs
, ip
->i_size
);
if (nb
< NDADDR
&& nb
< bn
) {
osize
= blksize(fs
, ip
, nb
);
if (osize
< fs
->fs_bsize
&& osize
> 0) {
error
= ffs_realloccg(ip
, nb
,
ffs_blkpref(ip
, nb
, (int)nb
, &ip
->i_db
[0]),
osize
, (int)fs
->fs_bsize
, cred
, &bp
);
ip
->i_size
= (nb
+ 1) * fs
->fs_bsize
;
vnode_pager_setsize(vp
, (u_long
)ip
->i_size
);
ip
->i_db
[nb
] = dbtofsb(fs
, bp
->b_blkno
);
* The first NDADDR blocks are direct blocks
if (nb
!= 0 && ip
->i_size
>= (bn
+ 1) * fs
->fs_bsize
) {
error
= bread(vp
, bn
, fs
->fs_bsize
, NOCRED
, &bp
);
* Consider need to reallocate a fragment.
osize
= fragroundup(fs
, blkoff(fs
, ip
->i_size
));
nsize
= fragroundup(fs
, size
);
error
= bread(vp
, bn
, osize
, NOCRED
, &bp
);
error
= ffs_realloccg(ip
, bn
,
ffs_blkpref(ip
, bn
, (int)bn
, &ip
->i_db
[0]),
osize
, nsize
, cred
, &bp
);
if (ip
->i_size
< (bn
+ 1) * fs
->fs_bsize
)
nsize
= fragroundup(fs
, size
);
error
= ffs_alloc(ip
, bn
,
ffs_blkpref(ip
, bn
, (int)bn
, &ip
->i_db
[0]),
bp
= getblk(vp
, bn
, nsize
);
bp
->b_blkno
= fsbtodb(fs
, newb
);
ip
->i_db
[bn
] = dbtofsb(fs
, bp
->b_blkno
);
* Determine the number of levels of indirection.
for (j
= NIADDR
; j
> 0; j
--) {
* Fetch the first indirect block allocating if necessary.
nb
= ip
->i_ib
[NIADDR
- j
];
pref
= ffs_blkpref(ip
, lbn
, 0, (daddr_t
*)0);
if (error
= ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
,
bp
= getblk(ip
->i_devvp
, fsbtodb(fs
, nb
), fs
->fs_bsize
);
* Write synchronously so that indirect blocks
* never point at garbage.
if (error
= bwrite(bp
)) {
ffs_blkfree(ip
, nb
, fs
->fs_bsize
);
ip
->i_ib
[NIADDR
- j
] = nb
;
* Fetch through the indirect blocks, allocating as necessary.
error
= bread(ip
->i_devvp
, fsbtodb(fs
, nb
),
(int)fs
->fs_bsize
, NOCRED
, &bp
);
i
= (bn
/ sh
) % NINDIR(fs
);
pref
= ffs_blkpref(ip
, lbn
, 0, (daddr_t
*)0);
ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
nbp
= getblk(ip
->i_devvp
, fsbtodb(fs
, nb
), fs
->fs_bsize
);
* Write synchronously so that indirect blocks
* never point at garbage.
if (error
= bwrite(nbp
)) {
ffs_blkfree(ip
, nb
, fs
->fs_bsize
);
* If required, write synchronously, otherwise use
* delayed write. If this is the first instance of
* the delayed write, reassociate the buffer with the
* file so it will be written if the file is sync'ed.
} else if (bp
->b_flags
& B_DELWRI
) {
* Get the data block, allocating if necessary.
pref
= ffs_blkpref(ip
, lbn
, i
, &bap
[0]);
ffs_alloc(ip
, lbn
, pref
, (int)fs
->fs_bsize
, cred
, &newb
)) {
nbp
= getblk(vp
, lbn
, fs
->fs_bsize
);
nbp
->b_blkno
= fsbtodb(fs
, nb
);
* If required, write synchronously, otherwise use
* delayed write. If this is the first instance of
* the delayed write, reassociate the buffer with the
* file so it will be written if the file is sync'ed.
} else if (bp
->b_flags
& B_DELWRI
) {
error
= bread(vp
, lbn
, (int)fs
->fs_bsize
, NOCRED
, &nbp
);
nbp
= getblk(vp
, lbn
, fs
->fs_bsize
);
nbp
->b_blkno
= fsbtodb(fs
, nb
);