* Copyright (c) 1989 The Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)ufs_vfsops.c 7.22 (Berkeley) %G%
#include "../ufs/ufsmount.h"
#include "../ufs/inode.h"
struct vfsops ufs_vfsops
= {
struct ufsmount mounttab
[NMOUNT
];
* 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
;
mp
= (struct mount
*)malloc((u_long
)sizeof(struct mount
),
error
= mountfs(rootvp
, mp
);
free((caddr_t
)mp
, M_MOUNT
);
if (error
= vfs_lock(mp
)) {
(void)ufs_unmount(mp
, 0);
free((caddr_t
)mp
, M_MOUNT
);
mp
->m_vnodecovered
= (struct vnode
*)0;
bzero(fs
->fs_fsmnt
+ 1, sizeof(fs
->fs_fsmnt
) - 1);
(void) copystr(ROOTNAME
, ump
->um_mntname
, MNAMELEN
- 1, &size
);
bzero(ump
->um_mntname
+ size
, MNAMELEN
- size
);
ufs_mount(mp
, path
, data
, ndp
)
if (error
= copyin(data
, (caddr_t
)&args
, sizeof (struct ufs_args
)))
if ((error
= getmdev(&devvp
, args
.fspec
, ndp
)) != 0)
if ((mp
->m_flag
& M_UPDATE
) == 0) {
error
= mountfs(devvp
, mp
);
if (fs
->fs_ronly
&& (mp
->m_flag
& M_RDONLY
) == 0)
* Verify that the specified device is the one that
* is really being used for the root file system.
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
);
(void) copyinstr(args
.fspec
, ump
->um_mntname
, MNAMELEN
- 1, &size
);
bzero(ump
->um_mntname
+ size
, MNAMELEN
- size
);
* Common code for mount and mountroot
register struct ufsmount
*ump
;
struct ufsmount
*fmp
= NULL
;
dev_t dev
= devvp
->v_rdev
;
int ronly
= (mp
->m_flag
& M_RDONLY
) != 0;
for (ump
= &mounttab
[0]; ump
< &mounttab
[NMOUNT
]; ump
++) {
if (ump
->um_fs
== NULL
) {
} else if (dev
== ump
->um_dev
) {
return (EBUSY
); /* needs translation */
(*bdevsw
[major(dev
)].d_open
)(dev
, ronly
? FREAD
: FREAD
|FWRITE
,
if (VOP_IOCTL(devvp
, DIOCGPART
, (caddr_t
)&dpart
, FREAD
, NOCRED
) != 0)
size
= dpart
.disklab
->d_secsize
;
if (error
= bread(devvp
, SBLOCK
, SBSIZE
, NOCRED
, &bp
)) {
error
= EINVAL
; /* XXX also needs translation */
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
,
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
->m_data
= (qaddr_t
)ump
;
mp
->m_bsize
= fs
->fs_bsize
;
mp
->m_fsize
= fs
->fs_fsize
;
mp
->m_fsid
.val
[0] = (long)dev
;
mp
->m_fsid
.val
[1] = MOUNT_UFS
;
/* 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
);
free((caddr_t
)ump
->um_fs
, M_SUPERBLK
);
* Make a filesystem operational.
* Nothing to do at the moment.
register struct ufsmount
*ump
;
if ((error
= iflush(dev
, mp
->m_qinod
)) && !forcibly
)
if ((error
= iflush(dev
)) && !forcibly
)
* Here we have to iflush again to get rid of the quota inode.
* A drag, but it would be ugly to cheat, & this doesn't happen often.
(void)iflush(dev
, (struct inode
*)NULL
);
free((caddr_t
)fs
->fs_csp
[0], M_SUPERBLK
);
error
= closei(dev
, IFBLK
, fs
->fs_ronly
? FREAD
: FREAD
|FWRITE
);
* Return root of a filesystem
tip
.i_dev
= VFSTOUFS(mp
)->um_dev
;
tip
.i_vnode
.v_mount
= mp
;
error
= iget(&tip
, (ino_t
)ROOTINO
, &ip
);
* Get file system statistics.
register struct statfs
*sbp
;
register struct ufsmount
*ump
;
if (fs
->fs_magic
!= FS_MAGIC
)
sbp
->f_flags
= mp
->m_flag
&~ (M_MLOCK
|M_MWAIT
);
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
;
sbp
->f_ffree
= fs
->fs_cstotal
.cs_nifree
;
sbp
->f_fsid
= mp
->m_fsid
;
bcopy((caddr_t
)fs
->fs_fsmnt
, (caddr_t
)&sbp
->f_mntonname
[0], MNAMELEN
);
bcopy((caddr_t
)ump
->um_mntname
, (caddr_t
)&sbp
->f_mntfromname
[0],
* 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.
register struct inode
*ip
;
register struct ufsmount
*ump
= VFSTOUFS(mp
);
if (fs
== (struct fs
*)1)
* 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
;
error
= sbupdate(ump
, waitfor
);
* Write back each (modified) inode.
for (ip
= inode
; ip
< inodeNINODE
; ip
++) {
if (ip
->i_devvp
!= ump
->um_devvp
||
(ip
->i_flag
& ILOCKED
) != 0 || ITOV(ip
)->v_count
== 0 ||
(ip
->i_flag
& (IMOD
|IACC
|IUPD
|ICHG
)) == 0)
error
= iupdat(ip
, &time
, &time
, waitfor
== MNT_WAIT
);
* Force stale buffer cache information to be flushed.
bflush(ump
->um_devvp
->v_mount
);
* 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
;
ufhp
= (struct ufid
*)fhp
;
fs
= VFSTOUFS(mp
)->um_fs
;
if (ufhp
->ufid_ino
< ROOTINO
||
ufhp
->ufid_ino
>= fs
->fs_ncg
* fs
->fs_ipg
) {
*vpp
= (struct vnode
*)0;
tip
.i_dev
= VFSTOUFS(mp
)->um_dev
;
tip
.i_vnode
.v_mount
= mp
;
if (error
= iget(&tip
, ufhp
->ufid_ino
, &ip
)) {
*vpp
= (struct vnode
*)0;
*vpp
= (struct vnode
*)0;
if (ip
->i_gen
!= ufhp
->ufid_gen
) {
*vpp
= (struct vnode
*)0;
* 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
;
* Common code for mount and quota.
* Check that the user's argument is a reasonable
* thing on which to mount, and return the device number if so.
getmdev(devvpp
, fname
, ndp
)
register struct nameidata
*ndp
;
register struct vnode
*vp
;
ndp
->ni_nameiop
= LOOKUP
| LOCKLEAF
| FOLLOW
;
ndp
->ni_segflg
= UIO_USERSPACE
;
if (error
= namei(ndp
)) {
return (ENODEV
); /* needs translation */
if (vp
->v_type
!= VBLK
) {
if (major(vp
->v_rdev
) >= nblkdev
)