* Copyright (c) 1989, 1991 The Regents of the University of California.
* %sccs.include.redist.c%
* @(#)lfs_vfsops.c 7.66 (Berkeley) %G%
#include <sys/disklabel.h>
#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 int lfs_mountfs
__P((struct vnode
*, struct mount
*, struct proc
*));
struct vfsops lfs_vfsops
= {
panic("lfs_mountroot"); /* XXX -- implement */
lfs_mount(mp
, path
, data
, ndp
, p
)
register struct mount
*mp
;
register struct lfs
*fs
; /* LFS */
if (error
= copyin(data
, (caddr_t
)&args
, sizeof (struct ufs_args
)))
/* Until LFS can do NFS right. XXX */
if (args
.exflags
& MNT_EXPORTED
)
* Process export requests.
if ((args
.exflags
& MNT_EXPORTED
) || (mp
->mnt_flag
& MNT_EXPORTED
)) {
if (args
.exflags
& MNT_EXPORTED
)
mp
->mnt_flag
|= MNT_EXPORTED
;
mp
->mnt_flag
&= ~MNT_EXPORTED
;
if (args
.exflags
& MNT_EXRDONLY
)
mp
->mnt_flag
|= MNT_EXRDONLY
;
mp
->mnt_flag
&= ~MNT_EXRDONLY
;
mp
->mnt_exroot
= args
.exroot
;
* If updating, check whether changing from read-only to
* read/write; if there is no device name, that's all we do.
if (mp
->mnt_flag
& MNT_UPDATE
) {
if (fs
->fs_ronly
&& (mp
->mnt_flag
& MNT_RDONLY
) == 0)
if (fs
->lfs_ronly
&& (mp
->mnt_flag
& MNT_RDONLY
) == 0)
* Not an update, or updating the name: look up the name
* and verify that it refers to a sensible block device.
ndp
->ni_nameiop
= LOOKUP
| FOLLOW
;
ndp
->ni_segflg
= UIO_USERSPACE
;
ndp
->ni_dirp
= args
.fspec
;
if (error
= namei(ndp
, p
))
if (devvp
->v_type
!= VBLK
) {
if (major(devvp
->v_rdev
) >= nblkdev
) {
if ((mp
->mnt_flag
& MNT_UPDATE
) == 0)
error
= lfs_mountfs(devvp
, mp
, p
); /* LFS */
if (devvp
!= ump
->um_devvp
)
error
= EINVAL
; /* needs translation */
fs
= ump
->um_lfs
; /* LFS */
(void) copyinstr(path
, fs
->fs_fsmnt
, sizeof(fs
->fs_fsmnt
) - 1, &size
);
bzero(fs
->fs_fsmnt
+ size
, sizeof(fs
->fs_fsmnt
) - size
);
bcopy((caddr_t
)fs
->fs_fsmnt
, (caddr_t
)mp
->mnt_stat
.f_mntonname
,
(void) copyinstr(args
.fspec
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1,
bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
(void) ufs_statfs(mp
, &mp
->mnt_stat
, p
);
(void)copyinstr(path
, fs
->lfs_fsmnt
, sizeof(fs
->lfs_fsmnt
) - 1, &size
);
bzero(fs
->lfs_fsmnt
+ size
, sizeof(fs
->lfs_fsmnt
) - size
);
bcopy((caddr_t
)fs
->lfs_fsmnt
, (caddr_t
)mp
->mnt_stat
.f_mntonname
,
(void) copyinstr(args
.fspec
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1,
bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
(void) lfs_statfs(mp
, &mp
->mnt_stat
, p
);
* Common code for mount and mountroot
lfs_mountfs(devvp
, mp
, p
)
register struct vnode
*devvp
;
extern struct vnode
*rootvp
;
register struct ufsmount
*ump
;
int error
, i
, ronly
, size
;
if (error
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, NOCRED
, p
))
if (VOP_IOCTL(devvp
, DIOCGPART
, (caddr_t
)&dpart
, FREAD
, NOCRED
, p
) != 0)
size
= dpart
.disklab
->d_secsize
;
dpart
.part
->p_fstype
= FS_LFS
;
dpart
.part
->p_fsize
= fs
->lfs_fsize
; /* frag size */
dpart
.part
->p_frag
= fs
->lfs_frag
; /* frags per block */
dpart
.part
->p_cpg
= fs
->lfs_segshift
; /* segment shift */
/* Don't free random space on error. */
/* Read in the superblock. */
if (error
= bread(devvp
, LFS_LABELPAD
/ size
, LFS_SBPAD
, NOCRED
, &bp
))
error
= EINVAL
; /* XXX needs translation */
/* Allocate the mount structure, copy the superblock into it. */
ump
= (struct ufsmount
*)malloc(sizeof *ump
, M_UFSMNT
, M_WAITOK
);
ump
->um_lfs
= malloc(sizeof(struct lfs
), M_SUPERBLK
, M_WAITOK
);
bcopy(bp
->b_un
.b_addr
, ump
->um_lfs
, sizeof(struct lfs
));
if (sizeof(struct lfs
) < LFS_SBPAD
) /* XXX why? */
/* Set up the I/O information */
/* XXX NOTUSED: fs->lfs_seglist = NULL; */
/* Set the file system readonly/modify bits. */
/* Initialize the mount structure. */
mp
->mnt_data
= (qaddr_t
)ump
;
mp
->mnt_stat
.f_fsid
.val
[0] = (long)dev
;
mp
->mnt_stat
.f_fsid
.val
[1] = MOUNT_LFS
;
mp
->mnt_flag
|= MNT_LOCAL
;
for (i
= 0; i
< MAXQUOTAS
; i
++)
ump
->um_quotas
[i
] = NULLVP
;
/* Read the ifile disk inode and store it in a vnode. */
if (error
= bread(devvp
, fs
->lfs_idaddr
, fs
->lfs_bsize
, NOCRED
, &bp
))
if (error
= lfs_vcreate(mp
, LFS_IFILE_INUM
, &vp
))
/* The ifile inode is stored in the superblock. */
/* Copy the on-disk inode into place. */
ip
->i_din
= *lfs_ifind(fs
, LFS_IFILE_INUM
, bp
->b_un
.b_dino
);
/* Initialize the associated vnode */
vp
->v_type
= IFTOVT(ip
->i_mode
);
devvp
->v_specflags
|= SI_MOUNTEDON
;
(void)VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, NOCRED
, p
);
free(ump
->um_lfs
, M_SUPERBLK
);
mp
->mnt_data
= (qaddr_t
)0;
lfs_unmount(mp
, mntflags
, p
)
register struct ufsmount
*ump
;
register struct lfs
*fs
; /* LFS */
int i
, error
, ronly
, flags
= 0;
if (mntflags
& MNT_FORCE
) {
if (!doforce
|| mp
== rootfs
)
if (error
= lfs_segwrite(mp
, 1))
ndirty
= lfs_umountdebug(mp
);
printf("lfs_umountdebug: returned %d dirty\n", ndirty
);
if (mp
->mnt_flag
& MNT_QUOTA
) {
if (error
= vflush(mp
, NULLVP
, SKIPSYSTEM
|flags
))
for (i
= 0; i
< MAXQUOTAS
; i
++) {
if (ump
->um_quotas
[i
] == NULLVP
)
* Here we fall through to vflush again to ensure
* that we have gotten rid of all the system vnodes.
if (error
= vflush(mp
, NULLVP
, flags
))
* Get file system statistics
.
register struct statfs
*sbp
;
register struct ufsmount
*ump
;
if (fs
->lfs_magic
!= LFS_MAGIC
)
panic("lfs_statfs: magic");
sbp
->f_fsize
= fs
->lfs_bsize
;
sbp
->f_bsize
= fs
->lfs_bsize
;
sbp
->f_blocks
= fs
->lfs_dsize
;
sbp
->f_bfree
= fs
->lfs_bfree
;
sbp
->f_bavail
= (fs
->lfs_dsize
* (100 - fs
->lfs_minfree
) / 100) -
(fs
->lfs_dsize
- sbp
->f_bfree
);
sbp
->f_files
= fs
->lfs_nfiles
;
sbp
->f_ffree
= fs
->lfs_bfree
* INOPB(fs
);
if (sbp
!= &mp
->mnt_stat
) {
bcopy((caddr_t
)mp
->mnt_stat
.f_mntonname
,
(caddr_t
)&sbp
->f_mntonname
[0], MNAMELEN
);
bcopy((caddr_t
)mp
->mnt_stat
.f_mntfromname
,
(caddr_t
)&sbp
->f_mntfromname
[0], MNAMELEN
);
* Go through the disk queues to initiate sandbagged IO;
* go through the inodes to write those that have been modified;
* initiate the writing of the super block if it has been modified.
* Note: we are always called with the filesystem marked `MPBUSY'.
extern int crashandburn
, syncprt
;
static int sync_lock
, sync_want
;
* Meta data blocks are only marked dirty, not busy, so LFS syncs
* must be single threaded.
if (error
= tsleep(&sync_lock
, PLOCK
| PCATCH
, "lfs sync", 0))
/* All syncs must be checkpoints until roll-forward is implemented. */
error
= lfs_segwrite(mp
, 1);
* Have to be really careful about stale file handles:
* - check that the inode number is valid
* - call lfs_vget() to get the locked inode
* - check for an unallocated inode (i_mode == 0)
* - check that the generation number matches
* use ifile to see if inode is allocated instead of reading off disk
* what is the relationship between my generational number and the NFS
register struct mount
*mp
;
register struct inode
*ip
;
register struct ufid
*ufhp
;
ufhp
= (struct ufid
*)fhp
;
if (ufhp
->ufid_ino
< ROOTINO
)
if (error
= lfs_vget(mp
, ufhp
->ufid_ino
, &nvp
)) {
if (ip
->i_gen
!= ufhp
->ufid_gen
) {
* Vnode pointer to File handle
register struct inode
*ip
;
register struct ufid
*ufhp
;
ufhp
= (struct ufid
*)fhp
;
ufhp
->ufid_len
= sizeof(struct ufid
);
ufhp
->ufid_ino
= ip
->i_number
;
ufhp
->ufid_gen
= ip
->i_gen
;