-static int
-nullfs_statfs(mp, sbp, context)
- struct mount *mp;
- struct vfsstatfs *sbp;
- vfs_context_t context;
-{
- int error;
- struct vfsstatfs mstat;
-
-#ifdef NULLFS_DIAGNOSTIC
- printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
- MOUNTTONULLMOUNT(mp)->nullm_rootvp,
- NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
- );
-#endif
-
- bzero(&mstat, sizeof(mstat));
-
- error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, context);
- if (error)
- return (error);
-
- /* now copy across the "interesting" information and fake the rest */
- //sbp->f_type = mstat.f_type;
- sbp->f_flags = mstat.f_flags;
- sbp->f_bsize = mstat.f_bsize;
- sbp->f_iosize = mstat.f_iosize;
- sbp->f_blocks = mstat.f_blocks;
- sbp->f_bfree = mstat.f_bfree;
- sbp->f_bavail = mstat.f_bavail;
- sbp->f_files = mstat.f_files;
- sbp->f_ffree = mstat.f_ffree;
- return (0);
+ struct timespec tzero = {.tv_sec = 0, .tv_nsec = 0};
+
+ NULLFSDEBUG("%s\n", __FUNCTION__);
+
+ /* Set default capabilities in case the lower file system is gone */
+ memset(&capabilities, 0, sizeof(capabilities));
+ capabilities.capabilities[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_HIDDEN_FILES;
+ capabilities.valid[VOL_CAPABILITIES_FORMAT] = VOL_CAP_FMT_FAST_STATFS | VOL_CAP_FMT_HIDDEN_FILES;
+
+ if (nullfs_vfs_getlowerattr(vnode_mount(null_mp->nullm_lowerrootvp), &vfa, ctx) == 0) {
+ if (VFSATTR_IS_SUPPORTED(&vfa, f_capabilities)) {
+ memcpy(&capabilities, &vfa.f_capabilities, sizeof(capabilities));
+ /* don't support vget */
+ capabilities.capabilities[VOL_CAPABILITIES_FORMAT] &= ~(VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_PATH_FROM_ID);
+
+ capabilities.capabilities[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_HIDDEN_FILES; /* Always support UF_HIDDEN */
+
+ capabilities.valid[VOL_CAPABILITIES_FORMAT] &= ~(VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_PATH_FROM_ID);
+
+ capabilities.valid[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_HIDDEN_FILES; /* Always support UF_HIDDEN */
+
+ /* dont' support interfaces that only make sense on a writable file system
+ * or one with specific vnops implemented */
+ capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] = 0;
+
+ capabilities.valid[VOL_CAPABILITIES_INTERFACES] &=
+ ~(VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_READDIRATTR | VOL_CAP_INT_EXCHANGEDATA |
+ VOL_CAP_INT_COPYFILE | VOL_CAP_INT_ALLOCATE | VOL_CAP_INT_VOL_RENAME | VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK);
+ }
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_create_time)) {
+ VFSATTR_RETURN(vfap, f_create_time, tzero);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_modify_time)) {
+ VFSATTR_RETURN(vfap, f_modify_time, tzero);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_access_time)) {
+ VFSATTR_RETURN(vfap, f_access_time, tzero);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_bsize)) {
+ VFSATTR_RETURN(vfap, f_bsize, sp->f_bsize);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_iosize)) {
+ VFSATTR_RETURN(vfap, f_iosize, sp->f_iosize);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_owner)) {
+ VFSATTR_RETURN(vfap, f_owner, 0);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_blocks)) {
+ VFSATTR_RETURN(vfap, f_blocks, sp->f_blocks);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_bfree)) {
+ VFSATTR_RETURN(vfap, f_bfree, sp->f_bfree);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_bavail)) {
+ VFSATTR_RETURN(vfap, f_bavail, sp->f_bavail);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_bused)) {
+ VFSATTR_RETURN(vfap, f_bused, sp->f_bused);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_files)) {
+ VFSATTR_RETURN(vfap, f_files, sp->f_files);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_ffree)) {
+ VFSATTR_RETURN(vfap, f_ffree, sp->f_ffree);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_fssubtype)) {
+ VFSATTR_RETURN(vfap, f_fssubtype, 0);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_capabilities)) {
+ memcpy(&vfap->f_capabilities, &capabilities, sizeof(vol_capabilities_attr_t));
+
+ VFSATTR_SET_SUPPORTED(vfap, f_capabilities);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_attributes)) {
+ vol_attributes_attr_t * volattr = &vfap->f_attributes;
+
+ volattr->validattr.commonattr = 0;
+ volattr->validattr.volattr = ATTR_VOL_NAME | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES;
+ volattr->validattr.dirattr = 0;
+ volattr->validattr.fileattr = 0;
+ volattr->validattr.forkattr = 0;
+
+ volattr->nativeattr.commonattr = 0;
+ volattr->nativeattr.volattr = ATTR_VOL_NAME | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES;
+ volattr->nativeattr.dirattr = 0;
+ volattr->nativeattr.fileattr = 0;
+ volattr->nativeattr.forkattr = 0;
+
+ VFSATTR_SET_SUPPORTED(vfap, f_attributes);
+ }
+
+ if (VFSATTR_IS_ACTIVE(vfap, f_vol_name)) {
+ /* The name of the volume is the same as the directory we mounted on */
+ coveredvp = vfs_vnodecovered(mp);
+ if (coveredvp) {
+ const char * name = vnode_getname_printable(coveredvp);
+ strlcpy(vfap->f_vol_name, name, MAXPATHLEN);
+ vnode_putname_printable(name);
+
+ VFSATTR_SET_SUPPORTED(vfap, f_vol_name);
+ vnode_put(coveredvp);
+ }
+ }
+
+ return 0;