* Copyright (c) 1986, 1989, 1991 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)lfs_inode.c 7.64 (Berkeley) %G%
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/lfs_extern.h>
static struct dinode
*lfs_ifind
__P((struct lfs
*, ino_t
, struct dinode
*));
* Look up an LFS dinode number to find its incore vnode. If not already
* in core, read it in from the specified device. Return the inode locked.
* Detection and handling of mount points must be done by the calling routine.
register struct inode
*ip
;
if ((*vpp
= ufs_ihashget(dev
, ino
)) != NULL
)
/* Translate the inode number to a disk address. */
if (ino
== LFS_IFILE_INUM
)
LFS_IENTRY(ifp
, fs
, ino
, bp
);
if (daddr
== LFS_UNUSED_DADDR
)
/* Allocate new vnode/inode. */
if (error
= lfs_vcreate(mntp
, ino
, &vp
)) {
* Put it onto its hash chain and lock it so that other requests for
* this inode will block if they arrive while we are sleeping waiting
* for old data structures to be purged or for the contents of the
* disk portion of this inode to be read.
* This may not need to be here, logically it should go down with
* the i_devvp initialization.
/* Read in the disk contents for the inode, copy into the inode. */
bread(ump
->um_devvp
, daddr
, (int)fs
->lfs_bsize
, NOCRED
, &bp
)) {
* The inode does not contain anything useful, so it
* would be misleading to leave it on its hash chain.
* Iput() will return it to the free list.
/* Unlock and discard unneeded inode. */
ip
->i_din
= *lfs_ifind(fs
, ino
, bp
->b_un
.b_dino
);
* Initialize the vnode from the inode, check for aliases. In all
* cases re-init ip, the underlying vnode/inode may have changed.
if (error
= ufs_vinit(mntp
, &lfs_specops
, LFS_FIFOOPS
, &vp
)) {
* Finish inode initialization now that aliasing has been resolved.
ip
->i_devvp
= ump
->um_devvp
;
/* Search a block for a specific dinode. */
register struct dinode
*dip
;
printf("lfs_ifind: inode %d\n", ino
);
for (cnt
= INOPB(fs
); cnt
--; ++dip
)
panic("lfs_ifind: dinode %u not found", ino
);
lfs_update(vp
, ta
, tm
, waitfor
)
register struct vnode
*vp
;
if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
if ((ip
->i_flag
& (IUPD
|IACC
|ICHG
|IMOD
)) == 0)
ip
->i_atime
.tv_sec
= ta
->tv_sec
;
ip
->i_mtime
.tv_sec
= tm
->tv_sec
;
INCRQUAD((ip
)->i_modrev
);
ip
->i_ctime
.tv_sec
= time
.tv_sec
;
ip
->i_flag
&= ~(IUPD
|IACC
|ICHG
|IMOD
);
/* Push back the vnode and any dirty blocks it may have. */
return (waitfor
? lfs_vflush(vp
) : 0);
/* Update segment usage information when removing a block. */
LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \
sup->su_nbytes -= num << fs->lfs_bshift; \
if (daddr != UNASSIGNED) { \
if (lastseg != (seg = datosn(fs, daddr))) { \
* Truncate the inode ip to at most length size. Update segment usage
lfs_truncate(vp
, length
, flags
, cred
)
register daddr_t
*daddrp
;
INDIR a
[NIADDR
+ 2], a_end
[NIADDR
+ 2];
daddr_t daddr
, lastblock
, lbn
, olastblock
;
long off
, blocksreleased
;
int error
, depth
, lastseg
, num
, offset
, seg
, size
;
printf("lfs_truncate\n");
vnode_pager_setsize(vp
, (u_long
)length
);
/* If truncating the file to 0, update the version number. */
LFS_IENTRY(ifp
, fs
, ip
->i_number
, bp
);
/* If length is larger than the file, just update the times. */
if (ip
->i_size
<= length
) {
return (lfs_update(vp
, &time
, &time
, 1));
* Calculate index into inode's block list of last direct and indirect
* blocks (if any) which we want to keep. Lastblock is 0 when the
* file is truncated to 0.
lastblock
= lblkno(fs
, length
+ fs
->lfs_bsize
- 1);
olastblock
= lblkno(fs
, ip
->i_size
+ fs
->lfs_bsize
- 1) - 1;
* Update the size of the file. If the file is not being truncated to
* a block boundry, the contents of the partial block following the end
* of the file must be zero'ed in case it ever become accessable again
* because of subsequent file growth.
offset
= blkoff(fs
, length
);
lbn
= lblkno(fs
, length
);
if (error
= getinoquota(ip
))
if (error
= bread(vp
, lbn
, fs
->lfs_bsize
, NOCRED
, &bp
))
(void)vnode_pager_uncache(vp
);
bzero(bp
->b_un
.b_addr
+ offset
, (unsigned)(size
- offset
));
* Modify sup->su_nbyte counters for each deleted block; keep track
* of number of blocks removed for ip->i_blocks.
for (lbn
= olastblock
; lbn
>= lastblock
;) {
lfs_bmaparray(vp
, lbn
, &daddr
, a
, &depth
);
for (i
= NIADDR
+ 2; i
--;)
case 0: /* Direct block. */
case 1: /* An indirect block. */
panic("lfs_truncate: lfs_bmaparray returned depth 1");
default: /* Chain of indirect blocks. */
if (inp
->in_off
> 0 && lbn
!= lastblock
) {
lbn
-= inp
->in_off
< lbn
- lastblock
?
inp
->in_off
: lbn
- lastblock
;
for (; depth
&& (inp
->in_off
== 0 || lbn
== lastblock
);
* The indirect block may not yet exist, so
* bread will create one just so we can free
inp
->in_lbn
, fs
->lfs_bsize
, NOCRED
, &bp
))
panic("lfs_truncate: bread bno %d",
daddrp
= bp
->b_un
.b_daddr
+ inp
->in_off
;
i
++ <= a_end
[depth
].in_off
;) {
a_end
[depth
].in_off
= NINDIR(fs
) - 1;
bzero(bp
->b_un
.b_daddr
+ inp
->in_off
,
inp
->in_off
* sizeof(daddr_t
));
if (depth
== 0 && a
[1].in_off
== 0) {
if (lbn
== lastblock
|| lbn
<= NDADDR
)
ip
->i_blocks
-= blocksreleased
;
* Currently, we don't know when we allocate an indirect block, so
* ip->i_blocks isn't getting incremented appropriately. As a result,
* when we delete any indirect blocks, we get a bad number here.
(void)vinvalbuf(vp
, length
> 0);
error
= lfs_update(vp
, &time
, &time
, MNT_WAIT
);