Re: numerous statfs bugs
On Sun, Apr 24, 2016 at 01:48:04PM +0200, Stefan Kempf wrote: > > Diff reads good to me. Any reason why you changed setting f_mntfromname > from "fusefs" to "fuse"? No, it's a typo; updated diff below. Thanks! 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.c27 Mar 2016 11:39:37 - 1.77 +++ isofs/cd9660/cd9660_vfsops.c19 Apr 2016 18:52:52 - @@ -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 != >mnt_stat) { - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, - MNAMELEN); - bcopy(>mnt_stat.mount_info.iso_args, - >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 - 1.49 +++ isofs/udf/udf_vfsops.c 19 Apr 2016 18:52:52 - @@ -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 - 1.244 +++ kern/vfs_subr.c 19 Apr 2016 18:52:52 - @@ -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(>mount_info.ufs_args, >mnt_stat.mount_info.ufs_args, - sizeof(struct ufs_args)); + memcpy(>mount_info, >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 - 1.20 +++ miscfs/fuse/fuse_vfsops.c 19 Apr 2016 18:52:52 - @@ -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, "fusefs", MNAMELEN); + bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN); + strlcpy(mp->mnt_stat.f_mntfromspec, "fusefs", 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;
Re: numerous statfs bugs
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 >mnt_stat structure is > passed as the stat buffer to VFS_STATFS. When looking at the case where > (sb != >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 - 1.77 > +++ isofs/cd9660/cd9660_vfsops.c 19 Apr 2016 18:52:52 - > @@ -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 != >mnt_stat) { > - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); > - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, > - MNAMELEN); > - bcopy(>mnt_stat.mount_info.iso_args, > - >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.c27 Mar 2016 11:39:37 - 1.49 > +++ isofs/udf/udf_vfsops.c19 Apr 2016 18:52:52 - > @@ -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 - 1.244 > +++ kern/vfs_subr.c 19 Apr 2016 18:52:52 - > @@ -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(>mount_info.ufs_args, >mnt_stat.mount_info.ufs_args, > - sizeof(struct ufs_args)); > + memcpy(>mount_info, >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 - 1.20 > +++ miscfs/fuse/fuse_vfsops.c 19 Apr 2016 18:52:52 - > @@ -111,7 +111,9 @@ fusefs_mount(struct mount *mp, const
numerous statfs bugs
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 >mnt_stat structure is passed as the stat buffer to VFS_STATFS. When looking at the case where (sb != >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? 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.c27 Mar 2016 11:39:37 - 1.77 +++ isofs/cd9660/cd9660_vfsops.c19 Apr 2016 18:52:52 - @@ -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 != >mnt_stat) { - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, - MNAMELEN); - bcopy(>mnt_stat.mount_info.iso_args, - >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 - 1.49 +++ isofs/udf/udf_vfsops.c 19 Apr 2016 18:52:52 - @@ -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 - 1.244 +++ kern/vfs_subr.c 19 Apr 2016 18:52:52 - @@ -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(>mount_info.ufs_args, >mnt_stat.mount_info.ufs_args, - sizeof(struct ufs_args)); + memcpy(>mount_info, >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 - 1.20 +++ miscfs/fuse/fuse_vfsops.c 19 Apr 2016 18:52:52 - @@ -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")); +