* Copyright (c) 1986, 1989, 1991 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)lfs_inode.c 7.78 (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>
/* Search a block for a specific dinode. */
register struct dinode
*dip
;
register struct dinode
*ldip
;
for (cnt
= INOPB(fs
), ldip
= dip
+ (cnt
- 1); cnt
--; --ldip
)
if (ldip
->di_inum
== ino
)
panic("lfs_ifind: dinode %u not found", ino
);
struct vop_update_args
/* {
struct vnode
*vp
= ap
->a_vp
;
if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
if ((ip
->i_flag
& (IUPD
| IACC
| ICHG
| IMOD
)) == 0)
ip
->i_atime
.ts_sec
= ap
->a_ta
->tv_sec
;
ip
->i_mtime
.ts_sec
= ap
->a_tm
->tv_sec
;
ip
->i_ctime
.ts_sec
= time
.tv_sec
;
ip
->i_flag
&= ~(IUPD
|IACC
|ICHG
);
if (!(ip
->i_flag
& IMOD
))
++(VFSTOUFS(vp
->v_mount
)->um_lfs
->lfs_uinodes
);
/* If sync, push back the vnode and any dirty blocks it may have. */
return (ap
->a_waitfor
& LFS_SYNC
? lfs_vflush(vp
) : 0);
/* Update segment usage information when removing a block. */
LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \
if ((num << fs->lfs_bshift) > sup->su_nbytes) \
panic("lfs_truncate: negative bytes in segment %d\n", \
sup->su_nbytes -= num << fs->lfs_bshift; \
e1 = VOP_BWRITE(sup_bp); \
if (daddr != UNASSIGNED) { \
if (lastseg != (seg = datosn(fs, daddr))) { \
* Truncate the inode ip to at most length size. Update segment usage
struct vop_truncate_args
/* {
register daddr_t
*daddrp
;
register struct vnode
*vp
= ap
->a_vp
;
off_t length
= ap
->a_length
;
INDIR a
[NIADDR
+ 2], a_end
[NIADDR
+ 2];
daddr_t daddr
, lastblock
, lbn
, olastblock
;
long off
, blocksreleased
;
int e1
, e2
, depth
, lastseg
, num
, offset
, seg
, size
;
if (vp
->v_type
== VLNK
&& vp
->v_mount
->mnt_maxsymlinklen
> 0) {
panic("lfs_truncate: partial truncate of symlink");
bzero((char *)&ip
->i_shortlink
, (u_int
)ip
->i_size
);
return (VOP_UPDATE(vp
, &tv
, &tv
, 0));
vnode_pager_setsize(vp
, (u_long
)length
);
/* If length is larger than the file, just update the times. */
if (ip
->i_size
<= length
) {
return (VOP_UPDATE(vp
, &tv
, &tv
, 0));
* 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 (e1
= getinoquota(ip
))
if (e1
= 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
)
/* If truncating the file to 0, update the version number. */
LFS_IENTRY(ifp
, fs
, ip
->i_number
, bp
);
if (ip
->i_blocks
< fsbtodb(fs
, blocksreleased
))
panic("lfs_truncate: block count < 0");
ip
->i_blocks
-= fsbtodb(fs
, blocksreleased
);
fs
->lfs_bfree
+= fsbtodb(fs
, blocksreleased
);
* Traverse dirty block list counting number of dirty buffers
* that are being deleted out of the cache, so that the lfs_avail
for (bp
= vp
->v_dirtyblkhd
; bp
; bp
= bp
->b_blockf
)
if (bp
->b_flags
& B_LOCKED
)
fs
->lfs_avail
-= fsbtodb(fs
, 1);
e1
= vinvalbuf(vp
, length
> 0, ap
->a_cred
, ap
->a_p
);
e2
= VOP_UPDATE(vp
, &tv
, &tv
, 0);
return (e1
? e1
: e2
? e2
: 0);