diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -441,6 +441,7 @@ struct nfsmount *nmp; struct timespec mtime_save; int error, force_fid_err; + dev_t topfsid; error = 0; @@ -504,28 +505,30 @@ } /* - * For NFSv4, if the node's fsid is not equal to the mount point's - * fsid, return the low order 32bits of the node's fsid. This - * allows getcwd(3) to work. There is a chance that the fsid might - * be the same as a local fs, but since this is in an NFS mount - * point, I don't think that will cause any problems? + * For NFSv4, the server's export may be a tree of file systems + * where a fileno is a unique value within each file system. + * na_filesid[0,1] uniquely identify the server file system + * and nm_fsid[0,1] is the value for the root file system mounted. + * As such, the value of va_fsid generated by vn_fsid() represents + * the root file system on the server and a different value for + * va_fsid is needed for the other server file systems. This + * va_fsid is ideally unique for all of the server file systems, + * so a 64bit hash on na_filesid[0,1] is calculated. + * Although highly unlikely that the fnv_64_hash() will be + * the same as the root, test for this case and recalculate the hash. */ + vn_fsid(vp, vap); if (NFSHASNFSV4(nmp) && NFSHASHASSETFSID(nmp) && (nmp->nm_fsid[0] != np->n_vattr.na_filesid[0] || nmp->nm_fsid[1] != np->n_vattr.na_filesid[1])) { - /* - * va_fsid needs to be set to some value derived from - * np->n_vattr.na_filesid that is not equal - * vp->v_mount->mnt_stat.f_fsid[0], so that it changes - * from the value used for the top level server volume - * in the mounted subtree. - */ - vn_fsid(vp, vap); - if ((uint32_t)vap->va_fsid == np->n_vattr.na_filesid[0]) - vap->va_fsid = hash32_buf( - np->n_vattr.na_filesid, 2 * sizeof(uint64_t), 0); - } else - vn_fsid(vp, vap); + topfsid = vap->va_fsid; + vap->va_fsid = FNV1_64_INIT; + do { + vap->va_fsid = fnv_64_buf(np->n_vattr.na_filesid, + sizeof(np->n_vattr.na_filesid), vap->va_fsid); + } while (vap->va_fsid == topfsid); + } + np->n_attrstamp = time_second; if (vap->va_size != np->n_size) { if (vap->va_type == VREG) {