* Copyright (c) 1991 The Regents of the University of California.
* %sccs.include.redist.c%
* @(#)lfs_syscalls.c 7.27 (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>
(SP)->fip = (FINFO *) (&(SP)->fip->fi_blocks[(SP)->fip->fi_nblocks])
#define INC_FINFO(SP) ++((SEGSUM *)((SP)->segsum))->ss_nfinfo
#define DEC_FINFO(SP) --((SEGSUM *)((SP)->segsum))->ss_nfinfo
* Before committing to add something to a segment summary, make sure there
* is enough room. S is the bytes added to the summary.
if (sp->sum_bytes_left < (s)) { \
(void) lfs_writeseg(fs, sp); \
struct buf
*lfs_fakebuf
__P((struct vnode
*, int, size_t, caddr_t
));
* This will mark inodes and blocks dirty, so they are written into the log.
* It will block until all the blocks have been written. The segment create
* time passed in the block_info and inode_info structures is used to decide
* if the data is valid for each block (in case some process dirtied a block
* or inode that is being cleaned between the determination that a block is
* live and the lfs_markv call).
* -1/errno is return on error.
lfs_markv(p
, uap
, retval
)
fsid_t fsid
; /* file system */
BLOCK_INFO
*blkiov
; /* block array */
int blkcnt
; /* count of block array entries */
daddr_t b_daddr
, v_daddr
;
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
if ((mntp
= getvfs(&uap
->fsid
)) == NULL
)
/* Initialize a segment. */
sp
= malloc(sizeof(struct segment
), M_SEGMENT
, M_WAITOK
);
sp
->bpp
= malloc(((LFS_SUMMARY_SIZE
- sizeof(SEGSUM
)) /
sizeof(daddr_t
) + 1) * sizeof(struct buf
*), M_SEGMENT
, M_WAITOK
);
sp
->seg_flags
= SEGM_CKP
;
start
= malloc(cnt
* sizeof(BLOCK_INFO
), M_SEGMENT
, M_WAITOK
);
if (error
= copyin(uap
->blkiov
, start
, cnt
* sizeof(BLOCK_INFO
)))
/* Mark blocks/inodes dirty. */
fs
= VFSTOUFS(mntp
)->um_lfs
;
sp
->seg_flags
|= SEGM_CLEAN
;
for (v_daddr
= LFS_UNUSED_DADDR
, lastino
= LFS_UNUSED_INUM
,
blkp
= start
; cnt
--; ++blkp
) {
* Get the IFILE entry (only once) and see if the file still
if (lastino
!= blkp
->bi_inode
) {
if (lastino
!= LFS_UNUSED_INUM
) {
/* Finish up last file */
lfs_writeinode(fs
, sp
, ip
);
sizeof(FINFO
) - sizeof(daddr_t
);
CHECK_SEG(sizeof(FINFO
));
sp
->sum_bytes_left
-= sizeof(FINFO
) - sizeof(daddr_t
);
sp
->start_lbp
= &sp
->fip
->fi_blocks
[0];
sp
->fip
->fi_version
= blkp
->bi_version
;
sp
->fip
->fi_ino
= blkp
->bi_inode
;
lastino
= blkp
->bi_inode
;
if (blkp
->bi_inode
== LFS_IFILE_INUM
)
v_daddr
= fs
->lfs_idaddr
;
LFS_IENTRY(ifp
, fs
, blkp
->bi_inode
, bp
);
if (v_daddr
== LFS_UNUSED_DADDR
)
/* Get the vnode/inode. */
if (lfs_fastvget(mntp
, blkp
->bi_inode
, v_daddr
, &vp
,
blkp
->bi_lbn
== LFS_UNUSED_LBN
?
printf("lfs_markv: VFS_VGET failed (%d)\n",
lastino
= LFS_UNUSED_INUM
;
v_daddr
= LFS_UNUSED_DADDR
;
} else if (v_daddr
== LFS_UNUSED_DADDR
)
/* If this BLOCK_INFO didn't contain a block, keep going. */
if (blkp
->bi_lbn
== LFS_UNUSED_LBN
)
if (VOP_BMAP(vp
, blkp
->bi_lbn
, NULL
, &b_daddr
, NULL
) ||
b_daddr
!= blkp
->bi_daddr
)
* If we got to here, then we are keeping the block. If it
* is an indirect block, we want to actually put it in the
* buffer cache so that it can be updated in the finish_meta
* section. If it's not, we need to allocate a fake buffer
* so that writeseg can perform the copyin and write the buffer.
if (blkp
->bi_lbn
>= 0) /* Data Block */
bp
= lfs_fakebuf(vp
, blkp
->bi_lbn
, bsize
,
bp
= getblk(vp
, blkp
->bi_lbn
, bsize
);
if (!(bp
->b_flags
& (B_DELWRI
| B_DONE
| B_CACHE
)) &&
(error
= copyin(blkp
->bi_bp
, bp
->b_un
.b_addr
,
if (error
= VOP_BWRITE(bp
))
while (lfs_gatherblock(sp
, bp
, NULL
));
lfs_writeinode(fs
, sp
, ip
);
if (!sp
->fip
->fi_nblocks
) {
sp
->sum_bytes_left
+= sizeof(FINFO
) - sizeof(daddr_t
);
(void) lfs_writeseg(fs
, sp
);
free(sp
->bpp
, M_SEGMENT
);
* XXX If we come in to error 2, we might have indirect blocks that were
* updated and now have bad block pointers. I don't know what to do
/* Free up fakebuffers */
for (bpp
= --sp
->cbpp
; bpp
>= sp
->bpp
; --bpp
)
if ((*bpp
)->b_flags
& B_CALL
) {
free(sp
->bpp
, M_SEGMENT
);
* This will fill in the current disk address for arrays of blocks.
* -1/errno is return on error.
lfs_bmapv(p
, uap
, retval
)
fsid_t fsid
; /* file system */
BLOCK_INFO
*blkiov
; /* block array */
int blkcnt
; /* count of block array entries */
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
if ((mntp
= getvfs(&uap
->fsid
)) == NULL
)
start
= blkp
= malloc(cnt
* sizeof(BLOCK_INFO
), M_SEGMENT
, M_WAITOK
);
if (error
= copyin(uap
->blkiov
, blkp
, cnt
* sizeof(BLOCK_INFO
))) {
for (step
= cnt
; step
--; ++blkp
) {
if (blkp
->bi_lbn
== LFS_UNUSED_LBN
)
if (VFS_VGET(mntp
, blkp
->bi_inode
, &vp
))
daddr
= LFS_UNUSED_DADDR
;
if (VOP_BMAP(vp
, blkp
->bi_lbn
, NULL
, &daddr
, NULL
))
daddr
= LFS_UNUSED_DADDR
;
copyout(start
, uap
->blkiov
, cnt
* sizeof(BLOCK_INFO
));
* Mark the segment clean.
* -1/errno is return on error.
lfs_segclean(p
, uap
, retval
)
fsid_t fsid
; /* file system */
u_long segment
; /* segment number */
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
if ((mntp
= getvfs(&uap
->fsid
)) == NULL
)
fs
= VFSTOUFS(mntp
)->um_lfs
;
if (datosn(fs
, fs
->lfs_curseg
) == uap
->segment
)
LFS_SEGENTRY(sup
, fs
, uap
->segment
, bp
);
if (sup
->su_flags
& SEGUSE_ACTIVE
) {
fs
->lfs_avail
+= fsbtodb(fs
, fs
->lfs_ssize
) - 1;
fs
->lfs_bfree
+= (sup
->su_nsums
* LFS_SUMMARY_SIZE
/ DEV_BSIZE
) +
sup
->su_ninos
* btodb(fs
->lfs_bsize
);
sup
->su_flags
&= ~SEGUSE_DIRTY
;
LFS_CLEANERINFO(cip
, fs
, bp
);
* This will block until a segment in file system fsid is written. A timeout
* in milliseconds may be specified which will awake the cleaner automatically.
* An fsid of -1 means any file system, and a timeout of 0 means forever.
* -1/errno is return on error.
lfs_segwait(p
, uap
, retval
)
fsid_t fsid
; /* file system */
struct timeval
*tv
; /* timeout */
extern int lfs_allclean_wakeup
;
if (error
= suser(p
->p_ucred
, &p
->p_acflag
)) {
if (uap
->fsid
== (fsid_t
)-1)
addr
= &lfs_allclean_wakeup
;
if ((mntp
= getvfs(&uap
->fsid
)) == NULL
)
addr
= &VFSTOUFS(mntp
)->um_lfs
->lfs_nextseg
;
if ((mntp
= getvfs(&uap
->fsid
)) == NULL
)
addr
= &lfs_allclean_wakeup
;
addr
= &VFSTOUFS(mntp
)->um_lfs
->lfs_nextseg
;
if (error
= copyin(uap
->tv
, &atv
, sizeof(struct timeval
)))
timevaladd(&atv
, (struct timeval
*)&time
);
error
= tsleep(addr
, PCATCH
| PUSER
, "segment", timeout
);
return (error
== ERESTART
? EINTR
: 0);
* VFS_VGET call specialized for the cleaner. The cleaner already knows the
* daddr from the ifile, so don't look it up again. If the cleaner is
* processing IINFO structures, it may have the ondisk inode already, so
* don't go retrieving it again.
lfs_fastvget(mp
, ino
, daddr
, vpp
, dinp
)
register struct inode
*ip
;
if ((*vpp
= ufs_ihashget(dev
, ino
)) != NULL
) {
if (!(ip
->i_flag
& IMOD
)) {
++ump
->um_lfs
->lfs_uinodes
;
/* Allocate new vnode/inode. */
if (error
= lfs_vcreate(mp
, 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. */
if (error
= copyin(dinp
, &ip
->i_din
, sizeof(struct dinode
)))
if (error
= bread(ump
->um_devvp
, daddr
,
(int)ump
->um_lfs
->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(ump
->um_lfs
, ino
, bp
->b_un
.b_dino
);
/* Inode was just read from user space or disk, make sure it's locked */
* 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(mp
, lfs_specop_p
, LFS_FIFOOPS
, &vp
)) {
* Finish inode initialization now that aliasing has been resolved.
ip
->i_devvp
= ump
->um_devvp
;
++ump
->um_lfs
->lfs_uinodes
;
lfs_fakebuf(vp
, lbn
, size
, uaddr
)
bp
= lfs_newbuf(vp
, lbn
, 0);