* Copyright (c) 1991 The Regents of the University of California.
* %sccs.include.redist.c%
* @(#)lfs_syscalls.c 7.14 (Berkeley) %G%
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/lfs/lfs_extern.h>
* 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 */
INODE_INFO
*inoiov
; /* inode array */
int inocnt
; /* count of inode array entries */
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
if ((mntp
= getvfs(&uap
->fsid
)) == NULL
)
start
= malloc(cnt
* sizeof(BLOCK_INFO
), M_SEGMENT
, M_WAITOK
);
if (error
= copyin(uap
->blkiov
, start
, cnt
* sizeof(BLOCK_INFO
))) {
* Mark blocks/inodes dirty. Note that errors are mostly ignored. If
* we can't get the info, the block is probably not all that useful,
* and hopefully subsequent calls from the cleaner will fix everything.
fs
= VFSTOUFS(mntp
)->um_lfs
;
for (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
) {
lastino
= blkp
->bi_inode
;
LFS_IENTRY(ifp
, fs
, blkp
->bi_inode
, bp
);
if (daddr
== LFS_UNUSED_DADDR
)
* Get the vnode/inode. If the inode modification time is
* earlier than the segment in which the block was found then
* they have to be valid, skip other checks.
if (VFS_VGET(mntp
, blkp
->bi_inode
, &vp
))
* If modify time later than segment create time, see if the
* block has been replaced.
if (ip
->i_mtime
.ts_sec
> blkp
->bi_segcreate
&&
(VOP_BMAP(vp
, blkp
->bi_lbn
, NULL
, &daddr
) ||
daddr
!= blkp
->bi_daddr
)) {
/* Get the block (from core or the cleaner) and write it. */
bp
= getblk(vp
, blkp
->bi_lbn
, bsize
);
if (!(bp
->b_flags
& B_CACHE
) &&
(error
= copyin(blkp
->bi_bp
, bp
->b_un
.b_addr
, bsize
))) {
start
= malloc(cnt
* sizeof(INODE_INFO
), M_SEGMENT
, M_WAITOK
);
if (error
= copyin(uap
->inoiov
, start
, cnt
* sizeof(INODE_INFO
))) {
for (inop
= start
; cnt
--; ++inop
) {
LFS_IENTRY(ifp
, fs
, inop
->ii_inode
, bp
);
if (daddr
!= inop
->ii_daddr
)
* This is grossly inefficient since the cleaner just handed
* us a copy of the inode and we're going to have to seek
* to get our own. The fix requires creating a version of
* lfs_vget that takes the copy and uses it instead of reading
* from disk, if it's not already in the cache.
if (!VFS_VGET(mntp
, inop
->ii_inode
, &vp
)) {
VTOI(vp
)->i_flag
|= IMOD
;
return (lfs_segwrite(mntp
, 1));
* 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 (VFS_VGET(mntp
, blkp
->bi_inode
, &vp
))
daddr
= LFS_UNUSED_DADDR
;
if (VOP_BMAP(vp
, blkp
->bi_lbn
, NULL
, &daddr
))
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 */
printf("lfs_segclean\n");
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
if ((mntp
= getvfs(&uap
->fsid
)) == NULL
)
fs
= VFSTOUFS(mntp
)->um_lfs
;
LFS_SEGENTRY(sup
, fs
, uap
->segment
, bp
);
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
)))
error
= tsleep(addr
, PCATCH
| PUSER
, "segment", timeout
);
return (error
== ERESTART
? EINTR
: 0);