+ kauth_cred_rele(cred);
+ vnode_put(vp);
+ return (error);
+}
+
+/*
+ * The nfs_statfs code is complicated, and used by mountnfs(), so leave it as-is
+ * and handle VFS_GETATTR by calling nfs_statfs and copying fields.
+ */
+static int
+nfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context)
+{
+ int error = 0;
+
+ if (VFSATTR_IS_ACTIVE(fsap, f_bsize) ||
+ VFSATTR_IS_ACTIVE(fsap, f_iosize) ||
+ VFSATTR_IS_ACTIVE(fsap, f_blocks) ||
+ VFSATTR_IS_ACTIVE(fsap, f_bfree) ||
+ VFSATTR_IS_ACTIVE(fsap, f_bavail) ||
+ VFSATTR_IS_ACTIVE(fsap, f_bused) ||
+ VFSATTR_IS_ACTIVE(fsap, f_files) ||
+ VFSATTR_IS_ACTIVE(fsap, f_ffree)) {
+ struct vfsstatfs sb;
+
+ error = nfs_statfs(mp, &sb, context);
+ if (!error) {
+ VFSATTR_RETURN(fsap, f_bsize, sb.f_bsize);
+ VFSATTR_RETURN(fsap, f_iosize, sb.f_iosize);
+ VFSATTR_RETURN(fsap, f_blocks, sb.f_blocks);
+ VFSATTR_RETURN(fsap, f_bfree, sb.f_bfree);
+ VFSATTR_RETURN(fsap, f_bavail, sb.f_bavail);
+ VFSATTR_RETURN(fsap, f_bused, sb.f_blocks - sb.f_bfree);
+ VFSATTR_RETURN(fsap, f_files, sb.f_files);
+ VFSATTR_RETURN(fsap, f_ffree, sb.f_ffree);
+ }
+ }
+
+ if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) {
+ struct nfsmount *nmp;
+ struct nfsv3_pathconf pc;
+ u_int32_t caps, valid;
+ vnode_t vp;
+ int v3;
+
+ if (!(nmp = VFSTONFS(mp)))
+ return (ENXIO);
+ vp = nmp->nm_dvp;
+ v3 = (nmp->nm_flag & NFSMNT_NFSV3);
+
+ /*
+ * The capabilities[] array defines what this volume supports.
+ *
+ * The valid[] array defines which bits this code understands
+ * the meaning of (whether the volume has that capability or not).
+ * Any zero bits here means "I don't know what you're asking about"
+ * and the caller cannot tell whether that capability is
+ * present or not.
+ */
+ caps = valid = 0;
+ if (v3) {
+ /* try to get fsinfo if we haven't already */
+ if (!(nmp->nm_state & NFSSTA_GOTFSINFO)) {
+ nfs_fsinfo(nmp, vp, vfs_context_ucred(context),
+ vfs_context_proc(context));
+ if (!(nmp = VFSTONFS(vnode_mount(vp))))
+ return (ENXIO);
+ }
+ if (nmp->nm_state & NFSSTA_GOTFSINFO) {
+ /* fsinfo indicates (non)support of links and symlinks */
+ valid |= VOL_CAP_FMT_SYMBOLICLINKS |
+ VOL_CAP_FMT_HARDLINKS;
+ if (nmp->nm_fsinfo.fsproperties & NFSV3FSINFO_SYMLINK)
+ caps |= VOL_CAP_FMT_SYMBOLICLINKS;
+ if (nmp->nm_fsinfo.fsproperties & NFSV3FSINFO_LINK)
+ caps |= VOL_CAP_FMT_HARDLINKS;
+ /* if fsinfo indicates all pathconf info is the same, */
+ /* we can use it to report case attributes */
+ if ((nmp->nm_fsinfo.fsproperties & NFSV3FSINFO_HOMOGENEOUS) &&
+ !(nmp->nm_state & NFSSTA_GOTPATHCONF)) {
+ /* no cached pathconf info, try to get now */
+ error = nfs_pathconfrpc(vp, &pc,
+ vfs_context_ucred(context),
+ vfs_context_proc(context));
+ if (!(nmp = VFSTONFS(vnode_mount(vp))))
+ return (ENXIO);
+ if (!error) {
+ /* all files have the same pathconf info, */
+ /* so cache a copy of the results */
+ nfs_pathconf_cache(nmp, &pc);
+ }
+ }
+ if (nmp->nm_state & NFSSTA_GOTPATHCONF) {
+ valid |= VOL_CAP_FMT_CASE_SENSITIVE |
+ VOL_CAP_FMT_CASE_PRESERVING;
+ if (!(nmp->nm_fsinfo.pcflags &
+ NFSPCINFO_CASE_INSENSITIVE))
+ caps |= VOL_CAP_FMT_CASE_SENSITIVE;
+ if (nmp->nm_fsinfo.pcflags &
+ NFSPCINFO_CASE_PRESERVING)
+ caps |= VOL_CAP_FMT_CASE_PRESERVING;
+ }
+ /* Is server's max file size at least 2TB? */
+ if (nmp->nm_fsinfo.maxfilesize >= 0x20000000000ULL)
+ caps |= VOL_CAP_FMT_2TB_FILESIZE;
+ } else {
+ /*
+ * NFSv3 supports 64 bits of file size.
+ * Without FSINFO from the server, we'll
+ * just assume maxfilesize >= 2TB
+ */
+ caps |= VOL_CAP_FMT_2TB_FILESIZE;
+ }
+ }
+ fsap->f_capabilities.capabilities[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 |
+ caps;
+ 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 |
+ valid;
+
+ /*
+ * We don't support most of the interfaces.
+ *
+ * We MAY support locking, but we don't have any easy way of probing.
+ * We can tell if there's no lockd running or if locks have been
+ * disabled for a mount, so we can definitely answer NO in that case.
+ * Any attempt to send a request to lockd to test for locking support
+ * may cause the lazily-launched locking daemons to be started
+ * unnecessarily. So we avoid that. However, we do record if we ever
+ * successfully perform a lock operation on a mount point, so if it
+ * looks like lock ops have worked, we do report that we support them.
+ */
+ caps = valid = 0;
+ if ((!nfslockdvnode && !nfslockdwaiting) ||
+ (nmp->nm_flag & NFSMNT_NOLOCKS)) {
+ /* locks disabled on this mount, so they definitely won't work */
+ valid = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
+ } else if (nmp->nm_state & NFSSTA_LOCKSWORK) {
+ caps = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
+ valid = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK;
+ }
+ fsap->f_capabilities.capabilities[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 |
+ // VOL_CAP_INT_EXTENDED_SECURITY |
+ // VOL_CAP_INT_USERACCESS |
+ caps;
+ 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 |
+ // VOL_CAP_INT_EXTENDED_SECURITY |
+ // VOL_CAP_INT_USERACCESS |
+ valid;
+
+ fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
+ fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0;
+
+ fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
+ fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0;
+
+ VFSATTR_SET_SUPPORTED(fsap, f_capabilities);
+ }
+
+ if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) {
+ fsap->f_attributes.validattr.commonattr = 0;
+ fsap->f_attributes.validattr.volattr =
+ ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES;
+ fsap->f_attributes.validattr.dirattr = 0;
+ fsap->f_attributes.validattr.fileattr = 0;
+ fsap->f_attributes.validattr.forkattr = 0;
+
+ fsap->f_attributes.nativeattr.commonattr = 0;
+ fsap->f_attributes.nativeattr.volattr =
+ ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES;
+ fsap->f_attributes.nativeattr.dirattr = 0;
+ fsap->f_attributes.nativeattr.fileattr = 0;
+ fsap->f_attributes.nativeattr.forkattr = 0;
+
+ VFSATTR_SET_SUPPORTED(fsap, f_attributes);
+ }
+