+ sbp->f_blocks = (uint64_t)((unsigned long)fs->fs_dsize);
+ sbp->f_bfree = (uint64_t) ((unsigned long)(fs->fs_cstotal.cs_nbfree * fs->fs_frag +
+ fs->fs_cstotal.cs_nffree));
+ sbp->f_bavail = (uint64_t) ((unsigned long)freespace(fs, fs->fs_minfree));
+ sbp->f_files = (uint64_t) ((unsigned long)(fs->fs_ncg * fs->fs_ipg - ROOTINO));
+ sbp->f_ffree = (uint64_t) ((unsigned long)fs->fs_cstotal.cs_nifree);
+ return (0);
+}
+
+int
+ffs_vfs_getattr(mp, fsap, context)
+ struct mount *mp;
+ struct vfs_attr *fsap;
+ vfs_context_t context;
+{
+ struct ufsmount *ump;
+ struct fs *fs;
+ kauth_cred_t cred;
+ struct vnode *devvp;
+ struct buf *bp;
+ struct ufslabel *ulp;
+ char *offset;
+ int bs, error, length;
+
+ ump = VFSTOUFS(mp);
+ fs = ump->um_fs;
+ cred = vfs_context_ucred(context);
+
+ VFSATTR_RETURN(fsap, f_bsize, fs->fs_fsize);
+ VFSATTR_RETURN(fsap, f_iosize, fs->fs_bsize);
+ VFSATTR_RETURN(fsap, f_blocks, (uint64_t)((unsigned long)fs->fs_dsize));
+ VFSATTR_RETURN(fsap, f_bfree, (uint64_t)((unsigned long)
+ (fs->fs_cstotal.cs_nbfree * fs->fs_frag +
+ fs->fs_cstotal.cs_nffree)));
+ VFSATTR_RETURN(fsap, f_bavail, (uint64_t)((unsigned long)freespace(fs,
+ fs->fs_minfree)));
+ VFSATTR_RETURN(fsap, f_files, (uint64_t)((unsigned long)
+ (fs->fs_ncg * fs->fs_ipg - ROOTINO)));
+ VFSATTR_RETURN(fsap, f_ffree, (uint64_t)((unsigned long)
+ fs->fs_cstotal.cs_nifree));
+
+ if (VFSATTR_IS_ACTIVE(fsap, f_fsid)) {
+ fsap->f_fsid.val[0] = mp->mnt_vfsstat.f_fsid.val[0];
+ fsap->f_fsid.val[1] = mp->mnt_vfsstat.f_fsid.val[1];
+ VFSATTR_SET_SUPPORTED(fsap, f_fsid);
+ }
+
+ if (VFSATTR_IS_ACTIVE(fsap, f_vol_name)) {
+ devvp = ump->um_devvp;
+ bs = vfs_devblocksize(mp);
+
+ if (error = (int)buf_meta_bread(devvp,
+ (daddr64_t)(UFS_LABEL_OFFSET / bs),
+ MAX(bs, UFS_LABEL_SIZE), cred, &bp)) {
+ if (bp)
+ buf_brelse(bp);
+ return (error);
+ }
+
+ /*
+ * Since the disklabel is read directly by older user space
+ * code, make sure this buffer won't remain in the cache when
+ * we release it.
+ */
+ buf_setflags(bp, B_NOCACHE);
+
+ offset = buf_dataptr(bp) + (UFS_LABEL_OFFSET % bs);
+ ulp = (struct ufslabel *)offset;
+
+ if (ufs_label_check(ulp)) {
+ length = ulp->ul_namelen;
+#if REV_ENDIAN_FS
+ if (mp->mnt_flag & MNT_REVEND)
+ length = OSSwapInt16(length);
+#endif
+ if (length > 0 && length <= UFS_MAX_LABEL_NAME) {
+ bcopy(ulp->ul_name, fsap->f_vol_name, length);
+ fsap->f_vol_name[UFS_MAX_LABEL_NAME - 1] = '\0';
+ fsap->f_vol_name[length] = '\0';
+ }
+ }
+
+ buf_brelse(bp);
+ VFSATTR_SET_SUPPORTED(fsap, f_vol_name);
+ }
+
+ if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) {
+ fsap->f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] =
+ VOL_CAP_FMT_SYMBOLICLINKS |
+ VOL_CAP_FMT_HARDLINKS |
+ VOL_CAP_FMT_SPARSE_FILES |
+ VOL_CAP_FMT_CASE_SENSITIVE |
+ VOL_CAP_FMT_CASE_PRESERVING |
+ VOL_CAP_FMT_FAST_STATFS ;
+ fsap->f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES]
+ = VOL_CAP_INT_NFSEXPORT |
+ VOL_CAP_INT_VOL_RENAME |
+ VOL_CAP_INT_ADVLOCK |
+ VOL_CAP_INT_FLOCK;
+ fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1]
+ = 0;
+ fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2]
+ = 0;
+
+ /* Capabilities we know about: */
+ fsap->f_capabilities.valid[VOL_CAPABILITIES_FORMAT] =
+ VOL_CAP_FMT_PERSISTENTOBJECTIDS |
+ VOL_CAP_FMT_SYMBOLICLINKS |
+ VOL_CAP_FMT_HARDLINKS |
+ VOL_CAP_FMT_JOURNAL |
+ VOL_CAP_FMT_JOURNAL_ACTIVE |
+ VOL_CAP_FMT_NO_ROOT_TIMES |
+ VOL_CAP_FMT_SPARSE_FILES |
+ VOL_CAP_FMT_ZERO_RUNS |
+ VOL_CAP_FMT_CASE_SENSITIVE |
+ VOL_CAP_FMT_CASE_PRESERVING |
+ VOL_CAP_FMT_FAST_STATFS |
+ VOL_CAP_FMT_2TB_FILESIZE;
+ fsap->f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] =
+ VOL_CAP_INT_SEARCHFS |
+ VOL_CAP_INT_ATTRLIST |
+ VOL_CAP_INT_NFSEXPORT |
+ 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 ;
+ fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0;
+ fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0;
+
+ VFSATTR_SET_SUPPORTED(fsap, f_capabilities);