* Copyright (c) 1989, 1991 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* from: @(#)ufs_vfsops.c 7.56 (Berkeley) 6/28/91
#include "dkbad.h" /* XXX */
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
,
mp
->mnt_stat
.f_mntonname
[MNAMELEN
-1] = '\0';
(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
;
* Disallow multiple mounts of the same device.
* Disallow mounting of a device that is currently in use
* (except for root, which might share swap device for miniroot).
* Flush out any old buffers remaining from a previous use.
if (error
= mountedon(devvp
))
if (vcount(devvp
) > 1 && devvp
!= 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
))
if (fs
->fs_magic
!= FS_MAGIC
|| fs
->fs_bsize
> MAXBSIZE
||
fs
->fs_bsize
< sizeof(struct fs
)) {
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
;
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
;
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
))
ump
->um_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
error
= VOP_CLOSE(ump
->um_devvp
, ronly
? FREAD
: FREAD
|FWRITE
,
free((caddr_t
)fs
->fs_csp
[0], M_SUPERBLK
);
free((caddr_t
)fs
, M_SUPERBLK
);
free((caddr_t
)ump
, M_UFSMNT
);
mp
->mnt_data
= (qaddr_t
)0;
mp
->mnt_flag
&= ~MNT_LOCAL
;
* Check to see if a filesystem is mounted on a block device.
register struct vnode
*vp
;
register struct vnode
*vq
;
if (vp
->v_specflags
& SI_MOUNTEDON
)
if (vp
->v_flag
& VALIASED
) {
for (vq
= *vp
->v_hashchain
; vq
; vq
= vq
->v_specnext
) {
if (vq
->v_rdev
!= vp
->v_rdev
||
vq
->v_type
!= vp
->v_type
)
if (vq
->v_specflags
& SI_MOUNTEDON
)
* 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
->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 */
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
->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
;