summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2003-11-12 08:01:40 +0000
committermckusick <mckusick@FreeBSD.org>2003-11-12 08:01:40 +0000
commit6a4c30bccd39734b6409a2f64db2e39af69226d4 (patch)
tree9276085ba9980aaba9cc6dd96164deefa080feaf /sys/kern
parent35dbfd051029f3e008f4a6e06721ee5dc0952843 (diff)
downloadFreeBSD-src-6a4c30bccd39734b6409a2f64db2e39af69226d4.zip
FreeBSD-src-6a4c30bccd39734b6409a2f64db2e39af69226d4.tar.gz
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.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/syscalls.master18
-rw-r--r--sys/kern/vfs_bio.c4
-rw-r--r--sys/kern/vfs_cluster.c4
-rw-r--r--sys/kern/vfs_extattr.c309
-rw-r--r--sys/kern/vfs_syscalls.c309
5 files changed, 606 insertions, 38 deletions
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 5303969..dab5d43 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -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); }
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index c75362d..595d39c 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -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
diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c
index dc86fb9..3fa110b 100644
--- a/sys/kern/vfs_cluster.c
+++ b/sys/kern/vfs_cluster.c
@@ -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
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 3783010..a8900dc 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -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;
@@ -346,6 +354,13 @@ getfsstat(td, uap)
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.
@@ -358,7 +373,11 @@ getfsstat(td, uap)
vfs_unbusy(mp, td);
continue;
}
- 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;
+ sp = &sb;
+ }
error = copyout(sp, sfsp, sizeof(*sp));
if (error) {
vfs_unbusy(mp, td);
@@ -379,6 +398,266 @@ getfsstat(td, uap)
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);
+ continue;
+ }
+ if (sfsp && count < maxcount) {
+ sp = &mp->mnt_stat;
+ /*
+ * 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;
+ }
+ sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+ cvtstatfs(td, sp, &osb);
+ error = copyout(&osb, sfsp, sizeof(osb));
+ if (error) {
+ vfs_unbusy(mp, td);
+ return (error);
+ }
+ sfsp += sizeof(osb);
+ }
+ 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);
+}
+
+/*
+ * 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;
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 3783010..a8900dc 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -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;
@@ -346,6 +354,13 @@ getfsstat(td, uap)
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.
@@ -358,7 +373,11 @@ getfsstat(td, uap)
vfs_unbusy(mp, td);
continue;
}
- 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;
+ sp = &sb;
+ }
error = copyout(sp, sfsp, sizeof(*sp));
if (error) {
vfs_unbusy(mp, td);
@@ -379,6 +398,266 @@ getfsstat(td, uap)
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);
+ continue;
+ }
+ if (sfsp && count < maxcount) {
+ sp = &mp->mnt_stat;
+ /*
+ * 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;
+ }
+ sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+ cvtstatfs(td, sp, &osb);
+ error = copyout(&osb, sfsp, sizeof(osb));
+ if (error) {
+ vfs_unbusy(mp, td);
+ return (error);
+ }
+ sfsp += sizeof(osb);
+ }
+ 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);
+}
+
+/*
+ * 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;
OpenPOWER on IntegriCloud