+ case VFS_CTL_NSTATUS:
+ /*
+ * Return the status of this mount. This is much more
+ * information than VFS_CTL_QUERY. In addition to the
+ * vq_flags return the significant mount options along
+ * with the list of threads blocked on the mount and
+ * how long the threads have been waiting.
+ */
+
+ lck_mtx_lock(nfs_request_mutex);
+ lck_mtx_lock(&nmp->nm_lock);
+
+ /*
+ * Count the number of requests waiting for a reply.
+ * Note: there could be multiple requests from the same thread.
+ */
+ numThreads = 0;
+ TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
+ if (rq->r_nmp == nmp)
+ numThreads++;
+ }
+
+ /* Calculate total size of result buffer */
+ totlen = sizeof(struct netfs_status) + (numThreads * sizeof(uint64_t));
+
+ if (req->oldptr == USER_ADDR_NULL) { // Caller is querying buffer size
+ lck_mtx_unlock(&nmp->nm_lock);
+ lck_mtx_unlock(nfs_request_mutex);
+ return SYSCTL_OUT(req, NULL, totlen);
+ }
+ if (req->oldlen < totlen) { // Check if caller's buffer is big enough
+ lck_mtx_unlock(&nmp->nm_lock);
+ lck_mtx_unlock(nfs_request_mutex);
+ return (ERANGE);
+ }
+
+ MALLOC(nsp, struct netfs_status *, totlen, M_TEMP, M_WAITOK|M_ZERO);
+ if (nsp == NULL) {
+ lck_mtx_unlock(&nmp->nm_lock);
+ lck_mtx_unlock(nfs_request_mutex);
+ return (ENOMEM);
+ }
+ timeoutmask = NFSSTA_TIMEO | NFSSTA_LOCKTIMEO | NFSSTA_JUKEBOXTIMEO;
+ if (nmp->nm_state & timeoutmask)
+ nsp->ns_status |= VQ_NOTRESP;
+ if (nmp->nm_state & NFSSTA_DEAD)
+ nsp->ns_status |= VQ_DEAD;
+
+ (void) nfs_mountopts(nmp, nsp->ns_mountopts, sizeof(nsp->ns_mountopts));
+ nsp->ns_threadcount = numThreads;
+
+ /*
+ * Get the thread ids of threads waiting for a reply
+ * and find the longest wait time.
+ */
+ if (numThreads > 0) {
+ struct timeval now;
+ time_t sendtime;
+
+ microuptime(&now);
+ count = 0;
+ sendtime = now.tv_sec;
+ TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
+ if (rq->r_nmp == nmp) {
+ if (rq->r_start < sendtime)
+ sendtime = rq->r_start;
+ // A thread_id of zero is used to represent an async I/O request.
+ nsp->ns_threadids[count] =
+ rq->r_thread ? thread_tid(rq->r_thread) : 0;
+ if (++count >= numThreads)
+ break;
+ }
+ }
+ nsp->ns_waittime = now.tv_sec - sendtime;
+ }
+
+ lck_mtx_unlock(&nmp->nm_lock);
+ lck_mtx_unlock(nfs_request_mutex);
+
+ error = SYSCTL_OUT(req, nsp, totlen);
+ FREE(nsp, M_TEMP);
+ break;