* Copyright (c) 1989, 1991 The Regents of the University of California.
* %sccs.include.redist.c%
* @(#)ufs_vfsops.c 7.56 (Berkeley) %G%
struct vfsops ufs_vfsops
= {
* Flag to allow forcible unmounting.
* Called by vfs_mountroot when ufs is going to be mounted as root.
* Name is updated by mount(8) after booting.
#define ROOTNAME "root_device"
register struct mount
*mp
;
extern struct vnode
*rootvp
;
struct proc
*p
= curproc
; /* XXX */
mp
= (struct mount
*)malloc((u_long
)sizeof(struct mount
),
mp
->mnt_op
= &ufs_vfsops
;
mp
->mnt_flag
= MNT_RDONLY
;
error
= mountfs(rootvp
, mp
, p
);
free((caddr_t
)mp
, M_MOUNT
);
if (error
= vfs_lock(mp
)) {
(void)ufs_unmount(mp
, 0, p
);
free((caddr_t
)mp
, M_MOUNT
);
mp
->mnt_vnodecovered
= NULLVP
;
bzero(fs
->fs_fsmnt
, sizeof(fs
->fs_fsmnt
));
bcopy((caddr_t
)fs
->fs_fsmnt
, (caddr_t
)mp
->mnt_stat
.f_mntonname
,
(void) copystr(ROOTNAME
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1,
bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
(void) ufs_statfs(mp
, &mp
->mnt_stat
, p
);
ufs_mount(mp
, path
, data
, ndp
, p
)
register struct mount
*mp
;
if (error
= copyin(data
, (caddr_t
)&args
, sizeof (struct ufs_args
)))
* 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)
* 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
= mountfs(devvp
, mp
, p
);
if (devvp
!= ump
->um_devvp
)
error
= EINVAL
; /* needs translation */
(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
);
* Common code for mount and mountroot
register struct vnode
*devvp
;
register struct ufsmount
*ump
= (struct ufsmount
*)0;
dev_t dev
= devvp
->v_rdev
;
int ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
extern struct vnode
*rootvp
;
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
;
if (error
= bread(devvp
, SBLOCK
, SBSIZE
, NOCRED
, &bp
))
error
= EINVAL
; /* XXX needs translation */
ump
= (struct ufsmount
*)malloc(sizeof *ump
, M_UFSMNT
, M_WAITOK
);
ump
->um_fs
= (struct fs
*)malloc((u_long
)fs
->fs_sbsize
, M_SUPERBLK
,
bcopy((caddr_t
)bp
->b_un
.b_addr
, (caddr_t
)ump
->um_fs
,
if (fs
->fs_sbsize
< SBSIZE
)
dpart
.part
->p_fstype
= FS_BSDFFS
;
dpart
.part
->p_fsize
= fs
->fs_fsize
;
dpart
.part
->p_frag
= fs
->fs_frag
;
dpart
.part
->p_cpg
= fs
->fs_cpg
;
* If we have a disk label, force per-partition
* filesystem information to be correct
* and set correct current fsbtodb shift.
dpart
.part
->p_fstype
= FS_BSDFFS
;
dpart
.part
->p_fsize
= fs
->fs_fsize
;
dpart
.part
->p_frag
= fs
->fs_frag
;
* Save the original fsbtodb shift to restore on updates.
* (Console doesn't understand fsbtodb changes.)
fs
->fs_sparecon
[0] = fs
->fs_fsbtodb
;
for (fs
->fs_fsbtodb
= 0; i
> 1; i
>>= 1)
blks
= howmany(fs
->fs_cssize
, fs
->fs_fsize
);
base
= space
= (caddr_t
)malloc((u_long
)fs
->fs_cssize
, M_SUPERBLK
,
for (i
= 0; i
< blks
; i
+= fs
->fs_frag
) {
if (i
+ fs
->fs_frag
> blks
)
size
= (blks
- i
) * fs
->fs_fsize
;
tp
= bread(dev
, fsbtodb(fs
, fs
->fs_csaddr
+ i
), size
,
error
= bread(devvp
, fsbtodb(fs
, fs
->fs_csaddr
+ i
), size
,
free((caddr_t
)base
, M_SUPERBLK
);
bcopy((caddr_t
)bp
->b_un
.b_addr
, space
, (u_int
)size
);
fs
->fs_csp
[fragstoblks(fs
, i
)] = (struct csum
*)space
;
mp
->mnt_data
= (qaddr_t
)ump
;
mp
->mnt_stat
.f_fsid
.val
[0] = (long)dev
;
mp
->mnt_stat
.f_fsid
.val
[1] = MOUNT_UFS
;
mp
->mnt_flag
|= MNT_LOCAL
;
for (i
= 0; i
< MAXQUOTAS
; i
++)
ump
->um_quotas
[i
] = NULLVP
;
devvp
->v_specflags
|= SI_MOUNTEDON
;
/* Sanity checks for old file systems. XXX */
fs
->fs_npsect
= MAX(fs
->fs_npsect
, fs
->fs_nsect
); /* XXX */
fs
->fs_interleave
= MAX(fs
->fs_interleave
, 1); /* XXX */
if (fs
->fs_postblformat
== FS_42POSTBLFMT
) /* XXX */
fs
->fs_nrpos
= 8; /* XXX */
(void)VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, NOCRED
, p
);
free((caddr_t
)ump
->um_fs
, M_SUPERBLK
);
free((caddr_t
)ump
, M_UFSMNT
);
mp
->mnt_data
= (qaddr_t
)0;
* Make a filesystem operational.
* Nothing to do at the moment.
ufs_unmount(mp
, mntflags
, p
)
register struct ufsmount
*ump
;
int i
, error
, ronly
, flags
= 0;
if (mntflags
& MNT_FORCE
) {
if (!doforce
|| mp
== rootfs
)
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
))
error
= closei(dev
, IFBLK
, fs
->fs_ronly
? FREAD
: FREAD
|FWRITE
);
* Return root of a filesystem
register struct inode
*ip
;
ip
->i_dev
= VFSTOUFS(mp
)->um_dev
;
error
= iget(ip
, (ino_t
)ROOTINO
, &nip
);
* Do operations associated with quotas
ufs_quotactl(mp
, cmds
, uid
, arg
, p
)
struct ufsmount
*ump
= VFSTOUFS(mp
);
cmd
= cmds
>> SUBCMDSHIFT
;
if (uid
== p
->p_cred
->p_ruid
)
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
if ((u_int
)type
>= MAXQUOTAS
)
return (quotaon(p
, mp
, type
, arg
));
error
= quotaoff(p
, mp
, type
);
return (setquota(mp
, uid
, type
, arg
));
return (setuse(mp
, uid
, type
, arg
));
return (getquota(mp
, uid
, type
, arg
));
* Get file system statistics.
register struct statfs
*sbp
;
register struct ufsmount
*ump
;
if (fs
->fs_magic
!= FS_MAGIC
)
sbp
->f_fsize
= fs
->fs_fsize
;
sbp
->f_bsize
= fs
->fs_bsize
;
sbp
->f_blocks
= fs
->fs_dsize
;
sbp
->f_bfree
= fs
->fs_cstotal
.cs_nbfree
* fs
->fs_frag
+
fs
->fs_cstotal
.cs_nffree
;
sbp
->f_bavail
= (fs
->fs_dsize
* (100 - fs
->fs_minfree
) / 100) -
(fs
->fs_dsize
- sbp
->f_bfree
);
sbp
->f_files
= fs
->fs_ncg
* fs
->fs_ipg
- ROOTINO
;
sbp
->f_ffree
= fs
->fs_cstotal
.cs_nifree
;
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'.
register struct vnode
*vp
;
register struct inode
*ip
;
register struct ufsmount
*ump
= VFSTOUFS(mp
);
* Write back modified superblock.
* Consistency check that the superblock
* is still in the buffer cache.
if (fs
->fs_ronly
!= 0) { /* XXX */
printf("fs = %s\n", fs
->fs_fsmnt
);
panic("update: rofs mod");
fs
->fs_time
= time
.tv_sec
;
allerror
= sbupdate(ump
, waitfor
);
* Write back each (modified) inode.
for (vp
= mp
->mnt_mounth
; vp
; vp
= vp
->v_mountf
) {
* If the vnode that we are about to sync is no longer
* associated with this mount point, start over.
if ((ip
->i_flag
& (IMOD
|IACC
|IUPD
|ICHG
)) == 0 &&
vp
->v_dirtyblkhd
== NULL
)
if ((ip
->i_flag
& (IMOD
|IACC
|IUPD
|ICHG
)) &&
(error
= iupdat(ip
, &time
, &time
, 0)))
* Force stale file system control information to be flushed.
vflushbuf(ump
->um_devvp
, waitfor
== MNT_WAIT
? B_SYNC
: 0);
* Write a superblock and associated information back to disk.
register struct fs
*fs
= mp
->um_fs
;
bp
= getblk(mp
->m_dev
, (daddr_t
)fsbtodb(fs
, SBOFF
/ fs
->fs_fsize
),
(int)fs
->fs_sbsize
, fs
->fs_dbsize
);
bp
= getblk(mp
->um_devvp
, SBLOCK
, (int)fs
->fs_sbsize
);
bcopy((caddr_t
)fs
, bp
->b_un
.b_addr
, (u_int
)fs
->fs_sbsize
);
/* Restore compatibility to old file systems. XXX */
if (fs
->fs_postblformat
== FS_42POSTBLFMT
) /* XXX */
bp
->b_un
.b_fs
->fs_nrpos
= -1; /* XXX */
/* restore standard fsbtodb shift */
bp
->b_un
.b_fs
->fs_fsbtodb
= fs
->fs_sparecon
[0];
bp
->b_un
.b_fs
->fs_sparecon
[0] = 0;
blks
= howmany(fs
->fs_cssize
, fs
->fs_fsize
);
space
= (caddr_t
)fs
->fs_csp
[0];
for (i
= 0; i
< blks
; i
+= fs
->fs_frag
) {
if (i
+ fs
->fs_frag
> blks
)
size
= (blks
- i
) * fs
->fs_fsize
;
bp
= getblk(mp
->m_dev
, fsbtodb(fs
, fs
->fs_csaddr
+ i
), size
,
bp
= getblk(mp
->um_devvp
, fsbtodb(fs
, fs
->fs_csaddr
+ i
), size
);
bcopy(space
, bp
->b_un
.b_addr
, (u_int
)size
);
* Print out statistics on the current allocation of the buffer pool.
* Can be enabled to print out on every ``sync'' by setting "syncprt"
register struct buf
*bp
, *dp
;
int counts
[MAXBSIZE
/CLBYTES
+1];
static char *bname
[BQUEUES
] = { "LOCKED", "LRU", "AGE", "EMPTY" };
for (bp
= bfreelist
, i
= 0; bp
< &bfreelist
[BQUEUES
]; bp
++, i
++) {
for (j
= 0; j
<= MAXBSIZE
/CLBYTES
; j
++)
for (dp
= bp
->av_forw
; dp
!= bp
; dp
= dp
->av_forw
) {
counts
[dp
->b_bufsize
/CLBYTES
]++;
printf("%s: total-%d", bname
[i
], count
);
for (j
= 0; j
<= MAXBSIZE
/CLBYTES
; j
++)
printf(", %d-%d", j
* CLBYTES
, counts
[j
]);
* Have to be really careful about stale file handles:
* - check that the inode number is in range
* - call iget() to get the locked inode
* - check for an unallocated inode (i_mode == 0)
* - check that the generation number matches
register struct mount
*mp
;
register struct ufid
*ufhp
;
register struct inode
*ip
;
ufhp
= (struct ufid
*)fhp
;
fs
= VFSTOUFS(mp
)->um_fs
;
if (ufhp
->ufid_ino
< ROOTINO
||
ufhp
->ufid_ino
>= fs
->fs_ncg
* fs
->fs_ipg
) {
ip
->i_dev
= VFSTOUFS(mp
)->um_dev
;
if (error
= iget(ip
, ufhp
->ufid_ino
, &nip
)) {
if (ip
->i_gen
!= ufhp
->ufid_gen
) {
* Vnode pointer to File handle
register struct inode
*ip
= VTOI(vp
);
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
;