summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--bin/df/df.c48
-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
-rw-r--r--sys/sys/mount.h41
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c11
8 files changed, 676 insertions, 68 deletions
diff --git a/bin/df/df.c b/bin/df/df.c
index 97d6f94..83c7d2d 100644
--- a/bin/df/df.c
+++ b/bin/df/df.c
@@ -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;
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;
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index 61aeb84..5ebf578 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -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);
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index f78253e..e188ed4 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -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,
OpenPOWER on IntegriCloud