Update the statfs structure with 64-bit fields to allow

accurate reporting of multi-terabyte filesystem sizes.

You should build and boot a new kernel BEFORE doing a `make world'
as the new kernel will know about binaries using the old statfs
structure, but an old kernel will not know about the new system
calls that support the new statfs structure. Running an old kernel
after a `make world' will cause programs such as `df' that do a
statfs system call to fail with a bad system call.

Reviewed by:	Bruce Evans <bde@zeta.org.au>
Reviewed by:	Tim Robbins <tjr@freebsd.org>
Reviewed by:	Julian Elischer <julian@elischer.org>
Reviewed by:	the hoards of <arch@freebsd.org>
Sponsored by:   DARPA & NAI Labs.
This commit is contained in:
Kirk McKusick 2003-11-12 08:01:40 +00:00
parent a61575cf29
commit fde81c7d8e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=122537
8 changed files with 678 additions and 70 deletions

View File

@ -120,9 +120,9 @@ typedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t;
static unit_t unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA };
static char *getmntpt(const char *);
static size_t longwidth(long);
static size_t int64width(int64_t);
static char *makenetvfslist(void);
static void prthuman(const struct statfs *, size_t);
static void prthuman(const struct statfs *, int64_t);
static void prthumanval(double);
static void prtstat(struct statfs *, struct maxwidths *);
static size_t regetmntinfo(struct statfs **, long, const char **);
@ -371,7 +371,7 @@ unit_adjust(double *val)
}
static void
prthuman(const struct statfs *sfsp, size_t used)
prthuman(const struct statfs *sfsp, int64_t used)
{
prthumanval((double)sfsp->f_blocks * (double)sfsp->f_bsize);
@ -408,10 +408,10 @@ prthumanval(double bytes)
static void
prtstat(struct statfs *sfsp, struct maxwidths *mwp)
{
static long blocksize;
static u_long blocksize;
static int headerlen, timesthrough = 0;
static const char *header;
size_t used, availblks, inodes;
int64_t used, availblks, inodes;
if (++timesthrough == 1) {
mwp->mntfrom = max(mwp->mntfrom, strlen("Filesystem"));
@ -445,21 +445,23 @@ prtstat(struct statfs *sfsp, struct maxwidths *mwp)
if (hflag) {
prthuman(sfsp, used);
} else {
(void)printf(" %*ld %*ld %*ld",
(u_int)mwp->total, fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
(u_int)mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize),
(u_int)mwp->avail, fsbtoblk(sfsp->f_bavail, sfsp->f_bsize,
blocksize));
(void)printf(" %*qd %*qd %*qd",
(u_int)mwp->total,
(intmax_t)fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
(u_int)mwp->used,
(intmax_t)fsbtoblk(used, sfsp->f_bsize, blocksize),
(u_int)mwp->avail,
(intmax_t)fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
}
(void)printf(" %5.0f%%",
availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
if (iflag) {
inodes = sfsp->f_files;
used = inodes - sfsp->f_ffree;
(void)printf(" %*lu %*lu %4.0f%% ",
(u_int)mwp->iused, (u_long)used,
(u_int)mwp->ifree, sfsp->f_ffree,
inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
(void)printf(" %*qd %*qd %4.0f%% ",
(u_int)mwp->iused, (intmax_t)used,
(u_int)mwp->ifree, (intmax_t)sfsp->f_ffree,
inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
} else
(void)printf(" ");
(void)printf(" %s\n", sfsp->f_mntonname);
@ -472,27 +474,27 @@ prtstat(struct statfs *sfsp, struct maxwidths *mwp)
static void
update_maxwidths(struct maxwidths *mwp, const struct statfs *sfsp)
{
static long blocksize = 0;
static u_long blocksize = 0;
int dummy;
if (blocksize == 0)
getbsize(&dummy, &blocksize);
mwp->mntfrom = max(mwp->mntfrom, strlen(sfsp->f_mntfromname));
mwp->total = max(mwp->total, longwidth(fsbtoblk(sfsp->f_blocks,
mwp->total = max(mwp->total, int64width(
fsbtoblk((int64_t)sfsp->f_blocks, sfsp->f_bsize, blocksize)));
mwp->used = max(mwp->used, int64width(fsbtoblk((int64_t)sfsp->f_blocks -
(int64_t)sfsp->f_bfree, sfsp->f_bsize, blocksize)));
mwp->avail = max(mwp->avail, int64width(fsbtoblk(sfsp->f_bavail,
sfsp->f_bsize, blocksize)));
mwp->used = max(mwp->used, longwidth(fsbtoblk(sfsp->f_blocks -
sfsp->f_bfree, sfsp->f_bsize, blocksize)));
mwp->avail = max(mwp->avail, longwidth(fsbtoblk(sfsp->f_bavail,
sfsp->f_bsize, blocksize)));
mwp->iused = max(mwp->iused, longwidth(sfsp->f_files -
mwp->iused = max(mwp->iused, int64width((int64_t)sfsp->f_files -
sfsp->f_ffree));
mwp->ifree = max(mwp->ifree, longwidth(sfsp->f_ffree));
mwp->ifree = max(mwp->ifree, int64width(sfsp->f_ffree));
}
/* Return the width in characters of the specified long. */
static size_t
longwidth(long val)
int64width(int64_t val)
{
size_t len;

View File

@ -68,7 +68,7 @@
15 STD POSIX { int chmod(char *path, int mode); }
16 STD POSIX { int chown(char *path, int uid, int gid); }
17 MSTD BSD { int obreak(char *nsize); } break obreak_args int
18 STD BSD { int getfsstat(struct statfs *buf, long bufsize, \
18 COMPAT4 BSD { int getfsstat(struct ostatfs *buf, long bufsize, \
int flags); }
19 COMPAT POSIX { long lseek(int fd, long offset, int whence); }
20 MSTD POSIX { pid_t getpid(void); }
@ -252,8 +252,8 @@
155 MNOIMPL BSD { int nfssvc(int flag, caddr_t argp); }
156 COMPAT BSD { int getdirentries(int fd, char *buf, u_int count, \
long *basep); }
157 STD BSD { int statfs(char *path, struct statfs *buf); }
158 STD BSD { int fstatfs(int fd, struct statfs *buf); }
157 COMPAT4 BSD { int statfs(char *path, struct ostatfs *buf); }
158 COMPAT4 BSD { int fstatfs(int fd, struct ostatfs *buf); }
159 UNIMPL NOHIDE nosys
160 UNIMPL NOHIDE nosys
161 STD BSD { int getfh(char *fname, struct fhandle *fhp); }
@ -439,7 +439,7 @@
295 UNIMPL NOHIDE nosys
296 UNIMPL NOHIDE nosys
; XXX 297 is 300 in NetBSD
297 STD BSD { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); }
297 COMPAT4 BSD { int fhstatfs(const struct fhandle *u_fhp, struct ostatfs *buf); }
298 STD BSD { int fhopen(const struct fhandle *u_fhp, int flags); }
299 STD BSD { int fhstat(const struct fhandle *u_fhp, struct stat *sb); }
; syscall numbers for FreeBSD
@ -574,10 +574,12 @@
struct sf_hdtr *hdtr, off_t *sbytes, int flags); }
394 MSTD BSD { int mac_syscall(const char *policy, int call, \
void *arg); }
395 UNIMPL NOHIDE nosys
396 UNIMPL NOHIDE nosys
397 UNIMPL NOHIDE nosys
398 UNIMPL NOHIDE nosys
395 STD BSD { int getfsstat(struct statfs *buf, long bufsize, \
int flags); }
396 STD BSD { int statfs(char *path, struct statfs *buf); }
397 STD BSD { int fstatfs(int fd, struct statfs *buf); }
398 STD BSD { int fhstatfs(const struct fhandle *u_fhp, \
struct statfs *buf); }
399 UNIMPL NOHIDE nosys
400 MNOSTD BSD { int ksem_close(semid_t id); }
401 MNOSTD BSD { int ksem_post(semid_t id); }

View File

@ -3236,8 +3236,8 @@ bufdone(struct buf *bp)
(int) m->pindex, (int)(foff >> 32),
(int) foff & 0xffffffff, resid, i);
if (!vn_isdisk(vp, NULL))
printf(" iosize: %ld, lblkno: %jd, flags: 0x%x, npages: %d\n",
bp->b_vp->v_mount->mnt_stat.f_iosize,
printf(" iosize: %jd, lblkno: %jd, flags: 0x%x, npages: %d\n",
(intmax_t)bp->b_vp->v_mount->mnt_stat.f_iosize,
(intmax_t) bp->b_lblkno,
bp->b_flags, bp->b_npages);
else

View File

@ -327,8 +327,8 @@ cluster_rbuild(vp, filesize, lbn, blkno, size, run, fbp)
GIANT_REQUIRED;
KASSERT(size == vp->v_mount->mnt_stat.f_iosize,
("cluster_rbuild: size %ld != filesize %ld\n",
size, vp->v_mount->mnt_stat.f_iosize));
("cluster_rbuild: size %ld != filesize %jd\n",
size, (intmax_t)vp->v_mount->mnt_stat.f_iosize));
/*
* avoid a division

View File

@ -226,11 +226,10 @@ statfs(td, uap)
struct statfs *buf;
} */ *uap;
{
register struct mount *mp;
register struct statfs *sp;
struct mount *mp;
struct statfs *sp, sb;
int error;
struct nameidata nd;
struct statfs sb;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
if ((error = namei(&nd)) != 0)
@ -244,10 +243,15 @@ statfs(td, uap)
if (error)
return (error);
#endif
/*
* Set these in case the underlying filesystem fails to do so.
*/
sp->f_version = STATFS_VERSION;
sp->f_namemax = NAME_MAX;
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
error = VFS_STATFS(mp, sp, td);
if (error)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if (suser(td)) {
bcopy(sp, &sb, sizeof(sb));
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
@ -276,9 +280,8 @@ fstatfs(td, uap)
{
struct file *fp;
struct mount *mp;
register struct statfs *sp;
struct statfs *sp, sb;
int error;
struct statfs sb;
if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
return (error);
@ -292,10 +295,15 @@ fstatfs(td, uap)
return (error);
#endif
sp = &mp->mnt_stat;
/*
* Set these in case the underlying filesystem fails to do so.
*/
sp->f_version = STATFS_VERSION;
sp->f_namemax = NAME_MAX;
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
error = VFS_STATFS(mp, sp, td);
if (error)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if (suser(td)) {
bcopy(sp, &sb, sizeof(sb));
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
@ -323,8 +331,8 @@ getfsstat(td, uap)
int flags;
} */ *uap;
{
register struct mount *mp, *nmp;
register struct statfs *sp;
struct mount *mp, *nmp;
struct statfs *sp, sb;
caddr_t sfsp;
long count, maxcount, error;
@ -338,6 +346,184 @@ getfsstat(td, uap)
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
#endif
if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
if (sfsp && count < maxcount) {
sp = &mp->mnt_stat;
/*
* Set these in case the underlying filesystem
* fails to do so.
*/
sp->f_version = STATFS_VERSION;
sp->f_namemax = NAME_MAX;
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
/*
* If MNT_NOWAIT or MNT_LAZY is specified, do not
* refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
* overrides MNT_WAIT.
*/
if (((uap->flags & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
(uap->flags & MNT_WAIT)) &&
(error = VFS_STATFS(mp, sp, td))) {
mtx_lock(&mountlist_mtx);
nmp = TAILQ_NEXT(mp, mnt_list);
vfs_unbusy(mp, td);
continue;
}
if (suser(td)) {
bcopy(sp, &sb, sizeof(sb));
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
sp = &sb;
}
error = copyout(sp, sfsp, sizeof(*sp));
if (error) {
vfs_unbusy(mp, td);
return (error);
}
sfsp += sizeof(*sp);
}
count++;
mtx_lock(&mountlist_mtx);
nmp = TAILQ_NEXT(mp, mnt_list);
vfs_unbusy(mp, td);
}
mtx_unlock(&mountlist_mtx);
if (sfsp && count > maxcount)
td->td_retval[0] = maxcount;
else
td->td_retval[0] = count;
return (0);
}
#ifdef COMPAT_FREEBSD4
/*
* Get old format filesystem statistics.
*/
static void cvtstatfs(struct thread *, struct statfs *, struct ostatfs *);
#ifndef _SYS_SYSPROTO_H_
struct freebsd4_statfs_args {
char *path;
struct ostatfs *buf;
};
#endif
/* ARGSUSED */
int
freebsd4_statfs(td, uap)
struct thread *td;
struct freebsd4_statfs_args /* {
char *path;
struct ostatfs *buf;
} */ *uap;
{
struct mount *mp;
struct statfs *sp;
struct ostatfs osb;
int error;
struct nameidata nd;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
if ((error = namei(&nd)) != 0)
return (error);
mp = nd.ni_vp->v_mount;
sp = &mp->mnt_stat;
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(nd.ni_vp);
#ifdef MAC
error = mac_check_mount_stat(td->td_ucred, mp);
if (error)
return (error);
#endif
error = VFS_STATFS(mp, sp, td);
if (error)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
cvtstatfs(td, sp, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
/*
* Get filesystem statistics.
*/
#ifndef _SYS_SYSPROTO_H_
struct freebsd4_fstatfs_args {
int fd;
struct ostatfs *buf;
};
#endif
/* ARGSUSED */
int
freebsd4_fstatfs(td, uap)
struct thread *td;
struct freebsd4_fstatfs_args /* {
int fd;
struct ostatfs *buf;
} */ *uap;
{
struct file *fp;
struct mount *mp;
struct statfs *sp;
struct ostatfs osb;
int error;
if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
return (error);
mp = fp->f_vnode->v_mount;
fdrop(fp, td);
if (mp == NULL)
return (EBADF);
#ifdef MAC
error = mac_check_mount_stat(td->td_ucred, mp);
if (error)
return (error);
#endif
sp = &mp->mnt_stat;
error = VFS_STATFS(mp, sp, td);
if (error)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
cvtstatfs(td, sp, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
/*
* Get statistics on all filesystems.
*/
#ifndef _SYS_SYSPROTO_H_
struct freebsd4_getfsstat_args {
struct ostatfs *buf;
long bufsize;
int flags;
};
#endif
int
freebsd4_getfsstat(td, uap)
struct thread *td;
register struct freebsd4_getfsstat_args /* {
struct ostatfs *buf;
long bufsize;
int flags;
} */ *uap;
{
struct mount *mp, *nmp;
struct statfs *sp;
struct ostatfs osb;
caddr_t sfsp;
long count, maxcount, error;
maxcount = uap->bufsize / sizeof(struct ostatfs);
sfsp = (caddr_t)uap->buf;
count = 0;
mtx_lock(&mountlist_mtx);
for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
#ifdef MAC
if (mac_check_mount_stat(td->td_ucred, mp) != 0) {
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
#endif
if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
nmp = TAILQ_NEXT(mp, mnt_list);
@ -359,12 +545,13 @@ getfsstat(td, uap)
continue;
}
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
error = copyout(sp, sfsp, sizeof(*sp));
cvtstatfs(td, sp, &osb);
error = copyout(&osb, sfsp, sizeof(osb));
if (error) {
vfs_unbusy(mp, td);
return (error);
}
sfsp += sizeof(*sp);
sfsp += sizeof(osb);
}
count++;
mtx_lock(&mountlist_mtx);
@ -379,6 +566,98 @@ getfsstat(td, uap)
return (0);
}
/*
* Implement fstatfs() for (NFS) file handles.
*/
#ifndef _SYS_SYSPROTO_H_
struct freebsd4_fhstatfs_args {
struct fhandle *u_fhp;
struct ostatfs *buf;
};
#endif
int
freebsd4_fhstatfs(td, uap)
struct thread *td;
struct freebsd4_fhstatfs_args /* {
struct fhandle *u_fhp;
struct ostatfs *buf;
} */ *uap;
{
struct statfs *sp;
struct mount *mp;
struct vnode *vp;
struct ostatfs osb;
fhandle_t fh;
int error;
/*
* Must be super user
*/
error = suser(td);
if (error)
return (error);
if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
return (error);
if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
return (error);
mp = vp->v_mount;
sp = &mp->mnt_stat;
vput(vp);
#ifdef MAC
error = mac_check_mount_stat(td->td_ucred, mp);
if (error)
return (error);
#endif
if ((error = VFS_STATFS(mp, sp, td)) != 0)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
cvtstatfs(td, sp, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
/*
* Convert a new format statfs structure to an old format statfs structure.
*/
static void
cvtstatfs(td, nsp, osp)
struct thread *td;
struct statfs *nsp;
struct ostatfs *osp;
{
bzero(osp, sizeof(*osp));
osp->f_bsize = MIN(nsp->f_bsize, LONG_MAX);
osp->f_iosize = MIN(nsp->f_iosize, LONG_MAX);
osp->f_blocks = MIN(nsp->f_blocks, LONG_MAX);
osp->f_bfree = MIN(nsp->f_bfree, LONG_MAX);
osp->f_bavail = MIN(nsp->f_bavail, LONG_MAX);
osp->f_files = MIN(nsp->f_files, LONG_MAX);
osp->f_ffree = MIN(nsp->f_ffree, LONG_MAX);
osp->f_owner = nsp->f_owner;
osp->f_type = nsp->f_type;
osp->f_flags = nsp->f_flags;
osp->f_syncwrites = MIN(nsp->f_syncwrites, LONG_MAX);
osp->f_asyncwrites = MIN(nsp->f_asyncwrites, LONG_MAX);
osp->f_syncreads = MIN(nsp->f_syncreads, LONG_MAX);
osp->f_asyncreads = MIN(nsp->f_asyncreads, LONG_MAX);
bcopy(nsp->f_fstypename, osp->f_fstypename,
MIN(MFSNAMELEN, OMNAMELEN));
bcopy(nsp->f_mntonname, osp->f_mntonname,
MIN(MFSNAMELEN, OMNAMELEN));
bcopy(nsp->f_mntfromname, osp->f_mntfromname,
MIN(MFSNAMELEN, OMNAMELEN));
if (suser(td)) {
osp->f_fsid.val[0] = osp->f_fsid.val[1] = 0;
} else {
osp->f_fsid = nsp->f_fsid;
}
}
#endif /* COMPAT_FREEBSD4 */
/*
* Change current working directory to a given file descriptor.
*/
@ -3788,10 +4067,9 @@ fhstatfs(td, uap)
struct statfs *buf;
} */ *uap;
{
struct statfs *sp;
struct statfs *sp, sb;
struct mount *mp;
struct vnode *vp;
struct statfs sb;
fhandle_t fh;
int error;
@ -3817,9 +4095,14 @@ fhstatfs(td, uap)
if (error)
return (error);
#endif
/*
* Set these in case the underlying filesystem fails to do so.
*/
sp->f_version = STATFS_VERSION;
sp->f_namemax = NAME_MAX;
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if ((error = VFS_STATFS(mp, sp, td)) != 0)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if (suser(td)) {
bcopy(sp, &sb, sizeof(sb));
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;

View File

@ -226,11 +226,10 @@ statfs(td, uap)
struct statfs *buf;
} */ *uap;
{
register struct mount *mp;
register struct statfs *sp;
struct mount *mp;
struct statfs *sp, sb;
int error;
struct nameidata nd;
struct statfs sb;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
if ((error = namei(&nd)) != 0)
@ -244,10 +243,15 @@ statfs(td, uap)
if (error)
return (error);
#endif
/*
* Set these in case the underlying filesystem fails to do so.
*/
sp->f_version = STATFS_VERSION;
sp->f_namemax = NAME_MAX;
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
error = VFS_STATFS(mp, sp, td);
if (error)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if (suser(td)) {
bcopy(sp, &sb, sizeof(sb));
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
@ -276,9 +280,8 @@ fstatfs(td, uap)
{
struct file *fp;
struct mount *mp;
register struct statfs *sp;
struct statfs *sp, sb;
int error;
struct statfs sb;
if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
return (error);
@ -292,10 +295,15 @@ fstatfs(td, uap)
return (error);
#endif
sp = &mp->mnt_stat;
/*
* Set these in case the underlying filesystem fails to do so.
*/
sp->f_version = STATFS_VERSION;
sp->f_namemax = NAME_MAX;
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
error = VFS_STATFS(mp, sp, td);
if (error)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if (suser(td)) {
bcopy(sp, &sb, sizeof(sb));
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
@ -323,8 +331,8 @@ getfsstat(td, uap)
int flags;
} */ *uap;
{
register struct mount *mp, *nmp;
register struct statfs *sp;
struct mount *mp, *nmp;
struct statfs *sp, sb;
caddr_t sfsp;
long count, maxcount, error;
@ -338,6 +346,184 @@ getfsstat(td, uap)
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
#endif
if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
if (sfsp && count < maxcount) {
sp = &mp->mnt_stat;
/*
* Set these in case the underlying filesystem
* fails to do so.
*/
sp->f_version = STATFS_VERSION;
sp->f_namemax = NAME_MAX;
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
/*
* If MNT_NOWAIT or MNT_LAZY is specified, do not
* refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
* overrides MNT_WAIT.
*/
if (((uap->flags & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
(uap->flags & MNT_WAIT)) &&
(error = VFS_STATFS(mp, sp, td))) {
mtx_lock(&mountlist_mtx);
nmp = TAILQ_NEXT(mp, mnt_list);
vfs_unbusy(mp, td);
continue;
}
if (suser(td)) {
bcopy(sp, &sb, sizeof(sb));
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
sp = &sb;
}
error = copyout(sp, sfsp, sizeof(*sp));
if (error) {
vfs_unbusy(mp, td);
return (error);
}
sfsp += sizeof(*sp);
}
count++;
mtx_lock(&mountlist_mtx);
nmp = TAILQ_NEXT(mp, mnt_list);
vfs_unbusy(mp, td);
}
mtx_unlock(&mountlist_mtx);
if (sfsp && count > maxcount)
td->td_retval[0] = maxcount;
else
td->td_retval[0] = count;
return (0);
}
#ifdef COMPAT_FREEBSD4
/*
* Get old format filesystem statistics.
*/
static void cvtstatfs(struct thread *, struct statfs *, struct ostatfs *);
#ifndef _SYS_SYSPROTO_H_
struct freebsd4_statfs_args {
char *path;
struct ostatfs *buf;
};
#endif
/* ARGSUSED */
int
freebsd4_statfs(td, uap)
struct thread *td;
struct freebsd4_statfs_args /* {
char *path;
struct ostatfs *buf;
} */ *uap;
{
struct mount *mp;
struct statfs *sp;
struct ostatfs osb;
int error;
struct nameidata nd;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
if ((error = namei(&nd)) != 0)
return (error);
mp = nd.ni_vp->v_mount;
sp = &mp->mnt_stat;
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(nd.ni_vp);
#ifdef MAC
error = mac_check_mount_stat(td->td_ucred, mp);
if (error)
return (error);
#endif
error = VFS_STATFS(mp, sp, td);
if (error)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
cvtstatfs(td, sp, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
/*
* Get filesystem statistics.
*/
#ifndef _SYS_SYSPROTO_H_
struct freebsd4_fstatfs_args {
int fd;
struct ostatfs *buf;
};
#endif
/* ARGSUSED */
int
freebsd4_fstatfs(td, uap)
struct thread *td;
struct freebsd4_fstatfs_args /* {
int fd;
struct ostatfs *buf;
} */ *uap;
{
struct file *fp;
struct mount *mp;
struct statfs *sp;
struct ostatfs osb;
int error;
if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
return (error);
mp = fp->f_vnode->v_mount;
fdrop(fp, td);
if (mp == NULL)
return (EBADF);
#ifdef MAC
error = mac_check_mount_stat(td->td_ucred, mp);
if (error)
return (error);
#endif
sp = &mp->mnt_stat;
error = VFS_STATFS(mp, sp, td);
if (error)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
cvtstatfs(td, sp, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
/*
* Get statistics on all filesystems.
*/
#ifndef _SYS_SYSPROTO_H_
struct freebsd4_getfsstat_args {
struct ostatfs *buf;
long bufsize;
int flags;
};
#endif
int
freebsd4_getfsstat(td, uap)
struct thread *td;
register struct freebsd4_getfsstat_args /* {
struct ostatfs *buf;
long bufsize;
int flags;
} */ *uap;
{
struct mount *mp, *nmp;
struct statfs *sp;
struct ostatfs osb;
caddr_t sfsp;
long count, maxcount, error;
maxcount = uap->bufsize / sizeof(struct ostatfs);
sfsp = (caddr_t)uap->buf;
count = 0;
mtx_lock(&mountlist_mtx);
for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
#ifdef MAC
if (mac_check_mount_stat(td->td_ucred, mp) != 0) {
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
#endif
if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
nmp = TAILQ_NEXT(mp, mnt_list);
@ -359,12 +545,13 @@ getfsstat(td, uap)
continue;
}
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
error = copyout(sp, sfsp, sizeof(*sp));
cvtstatfs(td, sp, &osb);
error = copyout(&osb, sfsp, sizeof(osb));
if (error) {
vfs_unbusy(mp, td);
return (error);
}
sfsp += sizeof(*sp);
sfsp += sizeof(osb);
}
count++;
mtx_lock(&mountlist_mtx);
@ -379,6 +566,98 @@ getfsstat(td, uap)
return (0);
}
/*
* Implement fstatfs() for (NFS) file handles.
*/
#ifndef _SYS_SYSPROTO_H_
struct freebsd4_fhstatfs_args {
struct fhandle *u_fhp;
struct ostatfs *buf;
};
#endif
int
freebsd4_fhstatfs(td, uap)
struct thread *td;
struct freebsd4_fhstatfs_args /* {
struct fhandle *u_fhp;
struct ostatfs *buf;
} */ *uap;
{
struct statfs *sp;
struct mount *mp;
struct vnode *vp;
struct ostatfs osb;
fhandle_t fh;
int error;
/*
* Must be super user
*/
error = suser(td);
if (error)
return (error);
if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
return (error);
if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
return (error);
mp = vp->v_mount;
sp = &mp->mnt_stat;
vput(vp);
#ifdef MAC
error = mac_check_mount_stat(td->td_ucred, mp);
if (error)
return (error);
#endif
if ((error = VFS_STATFS(mp, sp, td)) != 0)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
cvtstatfs(td, sp, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
/*
* Convert a new format statfs structure to an old format statfs structure.
*/
static void
cvtstatfs(td, nsp, osp)
struct thread *td;
struct statfs *nsp;
struct ostatfs *osp;
{
bzero(osp, sizeof(*osp));
osp->f_bsize = MIN(nsp->f_bsize, LONG_MAX);
osp->f_iosize = MIN(nsp->f_iosize, LONG_MAX);
osp->f_blocks = MIN(nsp->f_blocks, LONG_MAX);
osp->f_bfree = MIN(nsp->f_bfree, LONG_MAX);
osp->f_bavail = MIN(nsp->f_bavail, LONG_MAX);
osp->f_files = MIN(nsp->f_files, LONG_MAX);
osp->f_ffree = MIN(nsp->f_ffree, LONG_MAX);
osp->f_owner = nsp->f_owner;
osp->f_type = nsp->f_type;
osp->f_flags = nsp->f_flags;
osp->f_syncwrites = MIN(nsp->f_syncwrites, LONG_MAX);
osp->f_asyncwrites = MIN(nsp->f_asyncwrites, LONG_MAX);
osp->f_syncreads = MIN(nsp->f_syncreads, LONG_MAX);
osp->f_asyncreads = MIN(nsp->f_asyncreads, LONG_MAX);
bcopy(nsp->f_fstypename, osp->f_fstypename,
MIN(MFSNAMELEN, OMNAMELEN));
bcopy(nsp->f_mntonname, osp->f_mntonname,
MIN(MFSNAMELEN, OMNAMELEN));
bcopy(nsp->f_mntfromname, osp->f_mntfromname,
MIN(MFSNAMELEN, OMNAMELEN));
if (suser(td)) {
osp->f_fsid.val[0] = osp->f_fsid.val[1] = 0;
} else {
osp->f_fsid = nsp->f_fsid;
}
}
#endif /* COMPAT_FREEBSD4 */
/*
* Change current working directory to a given file descriptor.
*/
@ -3788,10 +4067,9 @@ fhstatfs(td, uap)
struct statfs *buf;
} */ *uap;
{
struct statfs *sp;
struct statfs *sp, sb;
struct mount *mp;
struct vnode *vp;
struct statfs sb;
fhandle_t fh;
int error;
@ -3817,9 +4095,14 @@ fhstatfs(td, uap)
if (error)
return (error);
#endif
/*
* Set these in case the underlying filesystem fails to do so.
*/
sp->f_version = STATFS_VERSION;
sp->f_namemax = NAME_MAX;
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if ((error = VFS_STATFS(mp, sp, td)) != 0)
return (error);
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if (suser(td)) {
bcopy(sp, &sb, sizeof(sb));
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;

View File

@ -62,13 +62,41 @@ struct fid {
/*
* filesystem statistics
*/
#define MFSNAMELEN 16 /* length of type name including null */
#define MNAMELEN 88 /* size of on/from name bufs */
#define STATFS_VERSION 0x20030518 /* current version number */
struct statfs {
uint32_t f_version; /* structure version number */
uint32_t f_type; /* type of filesystem */
uint64_t f_flags; /* copy of mount exported flags */
uint64_t f_bsize; /* filesystem fragment size */
uint64_t f_iosize; /* optimal transfer block size */
uint64_t f_blocks; /* total data blocks in filesystem */
uint64_t f_bfree; /* free blocks in filesystem */
int64_t f_bavail; /* free blocks avail to non-superuser */
uint64_t f_files; /* total file nodes in filesystem */
int64_t f_ffree; /* free nodes avail to non-superuser */
uint64_t f_syncwrites; /* count of sync writes since mount */
uint64_t f_asyncwrites; /* count of async writes since mount */
uint64_t f_syncreads; /* count of sync reads since mount */
uint64_t f_asyncreads; /* count of async reads since mount */
uint64_t f_spare[10]; /* unused spare */
uint32_t f_namemax; /* maximum filename length */
uid_t f_owner; /* user that mounted the filesystem */
fsid_t f_fsid; /* filesystem id */
char f_charspare[80]; /* spare string space */
char f_fstypename[MFSNAMELEN]; /* filesystem type name */
char f_mntfromname[MNAMELEN]; /* mounted filesystem */
char f_mntonname[MNAMELEN]; /* directory on which mounted */
};
#define MFSNAMELEN 16 /* length of fs type name, including null */
#define MNAMELEN (88 - 2 * sizeof(long)) /* size of on/from name bufs */
#ifdef _KERNEL
#define OMFSNAMELEN 16 /* length of fs type name, including null */
#define OMNAMELEN (88 - 2 * sizeof(long)) /* size of on/from name bufs */
/* XXX getfsstat.2 is out of date with write and read counter changes here. */
/* XXX statfs.2 is out of date with read counter changes here. */
struct statfs {
struct ostatfs {
long f_spare2; /* placeholder */
long f_bsize; /* fundamental filesystem block size */
long f_iosize; /* optimal transfer block size */
@ -83,12 +111,12 @@ struct statfs {
int f_flags; /* copy of mount exported flags */
long f_syncwrites; /* count of sync writes since mount */
long f_asyncwrites; /* count of async writes since mount */
char f_fstypename[MFSNAMELEN]; /* fs type name */
char f_mntonname[MNAMELEN]; /* directory on which mounted */
char f_fstypename[OMFSNAMELEN]; /* fs type name */
char f_mntonname[OMNAMELEN]; /* directory on which mounted */
long f_syncreads; /* count of sync reads since mount */
long f_asyncreads; /* count of async reads since mount */
short f_spares1; /* unused spare */
char f_mntfromname[MNAMELEN];/* mounted filesystem */
char f_mntfromname[OMNAMELEN];/* mounted filesystem */
short f_spares2; /* unused spare */
/*
* XXX on machines where longs are aligned to 8-byte boundaries, there
@ -98,7 +126,6 @@ struct statfs {
long f_spare[2]; /* unused spare */
};
#ifdef _KERNEL
#define MMAXOPTIONLEN 65536 /* maximum length of a mount option */
TAILQ_HEAD(vnodelst, vnode);

View File

@ -1076,6 +1076,7 @@ ffs_statfs(mp, sbp, td)
fs = ump->um_fs;
if (fs->fs_magic != FS_UFS1_MAGIC && fs->fs_magic != FS_UFS2_MAGIC)
panic("ffs_statfs");
sbp->f_version = STATFS_VERSION;
sbp->f_bsize = fs->fs_fsize;
sbp->f_iosize = fs->fs_bsize;
sbp->f_blocks = fs->fs_dsize;
@ -1085,8 +1086,18 @@ ffs_statfs(mp, sbp, td)
dbtofsb(fs, fs->fs_pendingblocks);
sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
sbp->f_namemax = NAME_MAX;
if (sbp != &mp->mnt_stat) {
sbp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
sbp->f_type = mp->mnt_vfc->vfc_typenum;
sbp->f_syncwrites = mp->mnt_stat.f_syncwrites;
sbp->f_asyncwrites = mp->mnt_stat.f_asyncwrites;
sbp->f_syncreads = mp->mnt_stat.f_syncreads;
sbp->f_asyncreads = mp->mnt_stat.f_asyncreads;
sbp->f_owner = mp->mnt_stat.f_owner;
sbp->f_fsid = mp->mnt_stat.f_fsid;
bcopy((caddr_t)mp->mnt_stat.f_fstypename,
(caddr_t)&sbp->f_fstypename[0], MFSNAMELEN);
bcopy((caddr_t)mp->mnt_stat.f_mntonname,
(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
bcopy((caddr_t)mp->mnt_stat.f_mntfromname,