Martin Natano wrote:
> There seem to be a number of issues with statfs related code in the
> kernel. The first issue is inside of the copy_statfs_info() function
> which is designed to be used by the filesystem's .vfs_statfs
> implementations to copy data from mp->mnt_stat to the target stat
> buffer. copy_statfs_info() always copies the ufs_args from the
> mount_info union, although the function is also used by non-ufs
> filesystems. Copying the whole union instead of just one member should
> do the trick for the general case.
>
> statfs(2) returns incomplete information for most filesystems: cd9660,
> udf, msdosfs and nfsv2 don't set f_namemax. ntfs and ext2fs don't set
> f_namemeax and f_favail. fusefs doesn't set f_mntfromspec, f_favail and
> f_iosize.
>
> In sys_statfs(), the mount point specific &mp->mnt_stat structure is
> passed as the stat buffer to VFS_STATFS. When looking at the case where
> (sb != &mp->mnt-stat), the situation is even worse. cd9660, udf, fusefs,
> msdosfs, ntfs and ext2fs don't use copy_statfs_info(), so there is a lot
> of unset members in the stat buffer (f_fsid, f_owner, f_flags,
> f_syncwrites, f_asyncwrites, f_syncreads, f_asyncreads, f_mntonname,
> f_mntfromname and f_mntfromspec).
>
> nfs copies MNAMELEN bytes from a smaller buffer into f_mntonname, so
> there is garbage after the null byte.
>
> Diff below fixes all those issues. Ok?
Diff reads good to me. Any reason why you changed setting f_mntfromname
from "fusefs" to "fuse"?
> natano
>
>
> Index: isofs/cd9660/cd9660_vfsops.c
> ===================================================================
> RCS file: /cvs/src/sys/isofs/cd9660/cd9660_vfsops.c,v
> retrieving revision 1.77
> diff -u -p -r1.77 cd9660_vfsops.c
> --- isofs/cd9660/cd9660_vfsops.c 27 Mar 2016 11:39:37 -0000 1.77
> +++ isofs/cd9660/cd9660_vfsops.c 19 Apr 2016 18:52:52 -0000
> @@ -383,6 +383,7 @@ iso_mountfs(devvp, mp, p, argp)
> mp->mnt_data = (qaddr_t)isomp;
> mp->mnt_stat.f_fsid.val[0] = (long)dev;
> mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
> + mp->mnt_stat.f_namemax = NAME_MAX;
> mp->mnt_flag |= MNT_LOCAL;
> isomp->im_mountp = mp;
> isomp->im_dev = dev;
> @@ -650,13 +651,9 @@ cd9660_statfs(mp, sbp, p)
> sbp->f_bavail = 0; /* blocks free for non superuser */
> sbp->f_files = 0; /* total files */
> sbp->f_ffree = 0; /* free file nodes */
> - if (sbp != &mp->mnt_stat) {
> - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
> - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname,
> - MNAMELEN);
> - bcopy(&mp->mnt_stat.mount_info.iso_args,
> - &sbp->mount_info.iso_args, sizeof(struct iso_args));
> - }
> + sbp->f_favail = 0; /* file nodes free for non superuser */
> + copy_statfs_info(sbp, mp);
> +
> return (0);
> }
>
> Index: isofs/udf/udf_vfsops.c
> ===================================================================
> RCS file: /cvs/src/sys/isofs/udf/udf_vfsops.c,v
> retrieving revision 1.49
> diff -u -p -r1.49 udf_vfsops.c
> --- isofs/udf/udf_vfsops.c 27 Mar 2016 11:39:37 -0000 1.49
> +++ isofs/udf/udf_vfsops.c 19 Apr 2016 18:52:52 -0000
> @@ -264,6 +264,7 @@ udf_mountfs(struct vnode *devvp, struct
> mp->mnt_data = (qaddr_t) ump;
> mp->mnt_stat.f_fsid.val[0] = devvp->v_rdev;
> mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
> + mp->mnt_stat.f_namemax = NAME_MAX;
> mp->mnt_flag |= MNT_LOCAL;
>
> ump->um_mountp = mp;
> @@ -542,6 +543,8 @@ udf_statfs(struct mount *mp, struct stat
> sbp->f_bavail = 0;
> sbp->f_files = 0;
> sbp->f_ffree = 0;
> + sbp->f_favail = 0;
> + copy_statfs_info(sbp, mp);
>
> return (0);
> }
> Index: kern/vfs_subr.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/vfs_subr.c,v
> retrieving revision 1.244
> diff -u -p -r1.244 vfs_subr.c
> --- kern/vfs_subr.c 7 Apr 2016 09:58:11 -0000 1.244
> +++ kern/vfs_subr.c 19 Apr 2016 18:52:52 -0000
> @@ -2276,6 +2276,6 @@ copy_statfs_info(struct statfs *sbp, con
> memcpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, MNAMELEN);
> memcpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname, MNAMELEN);
> memcpy(sbp->f_mntfromspec, mp->mnt_stat.f_mntfromspec, MNAMELEN);
> - memcpy(&sbp->mount_info.ufs_args, &mp->mnt_stat.mount_info.ufs_args,
> - sizeof(struct ufs_args));
> + memcpy(&sbp->mount_info, &mp->mnt_stat.mount_info,
> + sizeof(union mount_info));
> }
> Index: miscfs/fuse/fuse_vfsops.c
> ===================================================================
> RCS file: /cvs/src/sys/miscfs/fuse/fuse_vfsops.c,v
> retrieving revision 1.20
> diff -u -p -r1.20 fuse_vfsops.c
> --- miscfs/fuse/fuse_vfsops.c 27 Mar 2016 11:39:37 -0000 1.20
> +++ miscfs/fuse/fuse_vfsops.c 19 Apr 2016 18:52:52 -0000
> @@ -111,7 +111,9 @@ fusefs_mount(struct mount *mp, const cha
> bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
> strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
> bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
> - bcopy("fusefs", mp->mnt_stat.f_mntfromname, sizeof("fusefs"));
> + strlcpy(mp->mnt_stat.f_mntfromname, "fuse", MNAMELEN);
> + bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
> + strlcpy(mp->mnt_stat.f_mntfromspec, "fuse", MNAMELEN);
>
> fuse_device_set_fmp(fmp, 1);
> fbuf = fb_setup(0, 0, FBT_INIT, p);
> @@ -204,6 +206,8 @@ fusefs_statfs(struct mount *mp, struct s
>
> fmp = VFSTOFUSEFS(mp);
>
> + copy_statfs_info(sbp, mp);
> +
> if (fmp->sess_init) {
> fbuf = fb_setup(0, FUSE_ROOT_ID, FBT_STATFS, p);
>
> @@ -219,7 +223,9 @@ fusefs_statfs(struct mount *mp, struct s
> sbp->f_blocks = fbuf->fb_stat.f_blocks;
> sbp->f_files = fbuf->fb_stat.f_files;
> sbp->f_ffree = fbuf->fb_stat.f_ffree;
> + sbp->f_favail = fbuf->fb_stat.f_favail;
> sbp->f_bsize = fbuf->fb_stat.f_frsize;
> + sbp->f_iosize = fbuf->fb_stat.f_bsize;
> sbp->f_namemax = fbuf->fb_stat.f_namemax;
> fb_delete(fbuf);
> } else {
> @@ -227,8 +233,10 @@ fusefs_statfs(struct mount *mp, struct s
> sbp->f_bfree = 0;
> sbp->f_blocks = 0;
> sbp->f_ffree = 0;
> + sbp->f_favail = 0;
> sbp->f_files = 0;
> sbp->f_bsize = 0;
> + sbp->f_iosize = 0;
> sbp->f_namemax = 0;
> }
>
> Index: msdosfs/msdosfs_vfsops.c
> ===================================================================
> RCS file: /cvs/src/sys/msdosfs/msdosfs_vfsops.c,v
> retrieving revision 1.76
> diff -u -p -r1.76 msdosfs_vfsops.c
> --- msdosfs/msdosfs_vfsops.c 27 Mar 2016 11:39:37 -0000 1.76
> +++ msdosfs/msdosfs_vfsops.c 19 Apr 2016 18:52:52 -0000
> @@ -252,6 +252,11 @@ msdosfs_mount(struct mount *mp, const ch
> }
> }
>
> + if (pmp->pm_flags & MSDOSFSMNT_LONGNAME)
> + mp->mnt_stat.f_namemax = WIN_MAXLEN;
> + else
> + mp->mnt_stat.f_namemax = 12;
> +
> bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
> strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
> bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
> @@ -667,14 +672,9 @@ msdosfs_statfs(struct mount *mp, struct
> sbp->f_bfree = pmp->pm_freeclustercount;
> sbp->f_bavail = pmp->pm_freeclustercount;
> sbp->f_files = pmp->pm_RootDirEnts; /* XXX */
> - sbp->f_ffree = 0; /* what to put in here? */
> - if (sbp != &mp->mnt_stat) {
> - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
> - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
> - bcopy(&mp->mnt_stat.mount_info.msdosfs_args,
> - &sbp->mount_info.msdosfs_args, sizeof(struct msdosfs_args));
> - }
> - strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
> + sbp->f_ffree = sbp->f_favail = 0; /* what to put in here? */
> + copy_statfs_info(sbp, mp);
> +
> return (0);
> }
>
> Index: nfs/nfs_vfsops.c
> ===================================================================
> RCS file: /cvs/src/sys/nfs/nfs_vfsops.c,v
> retrieving revision 1.108
> diff -u -p -r1.108 nfs_vfsops.c
> --- nfs/nfs_vfsops.c 17 Mar 2016 18:52:31 -0000 1.108
> +++ nfs/nfs_vfsops.c 19 Apr 2016 18:52:52 -0000
> @@ -152,7 +152,6 @@ nfs_statfs(struct mount *mp, struct stat
> tquad = fxdr_hyper(&sfp->sf_ffiles);
> sbp->f_ffree = tquad;
> sbp->f_favail = tquad;
> - sbp->f_namemax = MAXNAMLEN;
> } else {
> sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize);
> sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks);
> @@ -160,6 +159,7 @@ nfs_statfs(struct mount *mp, struct stat
> sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail);
> sbp->f_files = 0;
> sbp->f_ffree = 0;
> + sbp->f_favail = 0;
> }
> copy_statfs_info(sbp, mp);
> m_freem(info.nmi_mrep);
> @@ -641,10 +641,13 @@ mountnfs(struct nfs_args *argp, struct m
> nmp->nm_acdirmin = NFS_MINATTRTIMO;
> nmp->nm_acdirmax = NFS_MAXATTRTIMO;
> bcopy(argp->fh, nmp->nm_fh, argp->fhsize);
> - strncpy(&mp->mnt_stat.f_fstypename[0], mp->mnt_vfc->vfc_name,
> MFSNAMELEN);
> - bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
> - bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
> - bcopy(hst, mp->mnt_stat.f_mntfromspec, MNAMELEN);
> + mp->mnt_stat.f_namemax = MAXNAMLEN;
> + memset(mp->mnt_stat.f_mntonname, 0, MNAMELEN);
> + strlcpy(mp->mnt_stat.f_mntonname, pth, MNAMELEN);
> + memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
> + strlcpy(mp->mnt_stat.f_mntfromname, hst, MNAMELEN);
> + memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN);
> + strlcpy(mp->mnt_stat.f_mntfromspec, hst, MNAMELEN);
> bcopy(argp, &mp->mnt_stat.mount_info.nfs_args, sizeof(*argp));
> nmp->nm_nam = nam;
> nfs_decode_args(nmp, argp, &mp->mnt_stat.mount_info.nfs_args);
> Index: ntfs/ntfs_vfsops.c
> ===================================================================
> RCS file: /cvs/src/sys/ntfs/ntfs_vfsops.c,v
> retrieving revision 1.49
> diff -u -p -r1.49 ntfs_vfsops.c
> --- ntfs/ntfs_vfsops.c 27 Mar 2016 11:39:37 -0000 1.49
> +++ ntfs/ntfs_vfsops.c 19 Apr 2016 18:52:52 -0000
> @@ -436,6 +436,7 @@ ntfs_mountfs(struct vnode *devvp, struct
>
> mp->mnt_stat.f_fsid.val[0] = dev;
> mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
> + mp->mnt_stat.f_namemax = NTFS_MAXFILENAME;
> mp->mnt_flag |= MNT_LOCAL;
> devvp->v_specmountpoint = mp;
> return (0);
> @@ -609,17 +610,10 @@ ntfs_statfs(struct mount *mp, struct sta
> sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
> sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
> sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree);
> - sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec;
> + sbp->f_ffree = sbp->f_favail = sbp->f_bfree / ntmp->ntm_bpmftrec;
> sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
> sbp->f_ffree;
> - sbp->f_flags = mp->mnt_flag;
> - if (sbp != &mp->mnt_stat) {
> - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
> - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
> - bcopy(&mp->mnt_stat.mount_info.ntfs_args,
> - &sbp->mount_info.ntfs_args, sizeof(struct ntfs_args));
> - }
> - strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
> + copy_statfs_info(sbp, mp);
>
> return (0);
> }
> Index: ufs/ext2fs/ext2fs_vfsops.c
> ===================================================================
> RCS file: /cvs/src/sys/ufs/ext2fs/ext2fs_vfsops.c,v
> retrieving revision 1.89
> diff -u -p -r1.89 ext2fs_vfsops.c
> --- ufs/ext2fs/ext2fs_vfsops.c 27 Mar 2016 11:39:37 -0000 1.89
> +++ ufs/ext2fs/ext2fs_vfsops.c 19 Apr 2016 18:52:53 -0000
> @@ -293,6 +293,7 @@ ext2fs_mount(struct mount *mp, const cha
> strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN);
> memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN);
> strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
> + memcpy(&mp->mnt_stat.mount_info.ufs_args, &args, sizeof(args));
>
> if (fs->e2fs_fmod != 0) { /* XXX */
> fs->e2fs_fmod = 0;
> @@ -583,6 +584,7 @@ ext2fs_mountfs(struct vnode *devvp, stru
> mp->mnt_data = (qaddr_t)ump;
> mp->mnt_stat.f_fsid.val[0] = (long)dev;
> mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
> + mp->mnt_stat.f_namemax = MAXNAMLEN;
> mp->mnt_flag |= MNT_LOCAL;
> ump->um_mountp = mp;
> ump->um_dev = dev;
> @@ -711,13 +713,9 @@ ext2fs_statfs(struct mount *mp, struct s
> sbp->f_bfree = fs->e2fs.e2fs_fbcount;
> sbp->f_bavail = sbp->f_bfree - fs->e2fs.e2fs_rbcount;
> sbp->f_files = fs->e2fs.e2fs_icount;
> - sbp->f_ffree = fs->e2fs.e2fs_ficount;
> - if (sbp != &mp->mnt_stat) {
> - memcpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, MNAMELEN);
> - memcpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname,
> MNAMELEN);
> - memcpy(sbp->f_mntfromspec, mp->mnt_stat.f_mntfromspec,
> MNAMELEN);
> - }
> - strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
> + sbp->f_favail = sbp->f_ffree = fs->e2fs.e2fs_ficount;
> + copy_statfs_info(sbp, mp);
> +
> return (0);
> }
>
> Index: ufs/mfs/mfs_extern.h
> ===================================================================
> RCS file: /cvs/src/sys/ufs/mfs/mfs_extern.h,v
> retrieving revision 1.18
> diff -u -p -r1.18 mfs_extern.h
> --- ufs/mfs/mfs_extern.h 21 Dec 2010 20:14:44 -0000 1.18
> +++ ufs/mfs/mfs_extern.h 19 Apr 2016 18:52:53 -0000
> @@ -49,7 +49,6 @@ extern struct vops mfs_vops;
> int mfs_mount(struct mount *, const char *, void *, struct nameidata *,
> struct proc *);
> int mfs_start(struct mount *, int, struct proc *);
> -int mfs_statfs(struct mount *, struct statfs *, struct proc *);
> int mfs_init(struct vfsconf *);
> int mfs_checkexp(struct mount *, struct mbuf *, int *, struct ucred **);
>
> Index: ufs/mfs/mfs_vfsops.c
> ===================================================================
> RCS file: /cvs/src/sys/ufs/mfs/mfs_vfsops.c,v
> retrieving revision 1.49
> diff -u -p -r1.49 mfs_vfsops.c
> --- ufs/mfs/mfs_vfsops.c 14 Mar 2016 23:08:06 -0000 1.49
> +++ ufs/mfs/mfs_vfsops.c 19 Apr 2016 18:52:53 -0000
> @@ -65,7 +65,7 @@ const struct vfsops mfs_vfsops = {
> ffs_unmount,
> ufs_root,
> ufs_quotactl,
> - mfs_statfs,
> + ffs_statfs,
> ffs_sync,
> ffs_vget,
> ffs_fhtovp,
> @@ -207,22 +207,6 @@ mfs_start(struct mount *mp, int flags, s
> sleepreturn = tsleep((caddr_t)vp, mfs_pri, "mfsidl", 0);
> }
> return (0);
> -}
> -
> -/*
> - * Get file system statistics.
> - */
> -int
> -mfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
> -{
> - int error;
> -
> - error = ffs_statfs(mp, sbp, p);
> - strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
> - if (sbp != &mp->mnt_stat)
> - memcpy(&sbp->mount_info.mfs_args,
> - &mp->mnt_stat.mount_info.mfs_args, sizeof(struct mfs_args));
> - return (error);
> }
>
> /*
>