-
-/*
- * Check the nfs_lock_pid hash table for an entry and, if requested,
- * add the entry if it is not found.
- *
- * (Also, if adding, try to clean up some stale entries.)
- * (nfs_lock_mutex must be held)
- */
-static int
-nfs_lock_pid_check(proc_t p, int addflag)
-{
- struct nfs_lock_pid *lp, *lplru, *lplru_next, *mlp;
- TAILQ_HEAD(, nfs_lock_pid) nfs_lock_pid_free;
- proc_t plru = PROC_NULL;
- pid_t pid;
- int error = 0;
- struct timeval now;
-
- TAILQ_INIT(&nfs_lock_pid_free);
- mlp = NULL;
-
-loop:
- /* Search hash chain */
- pid = proc_pid(p);
- error = ENOENT;
- lp = NFS_LOCK_PID_HASH(pid)->lh_first;
- for (; lp != NULL; lp = lp->lp_hash.le_next)
- if (lp->lp_pid == pid) {
- /* found pid... */
- if (timevalcmp(&lp->lp_pid_start, &p->p_start, ==)) {
- /* ...and it's valid */
- /* move to tail of LRU */
- TAILQ_REMOVE(&nfs_lock_pid_lru, lp, lp_lru);
- microuptime(&now);
- lp->lp_time = now.tv_sec;
- TAILQ_INSERT_TAIL(&nfs_lock_pid_lru, lp, lp_lru);
- error = 0;
- break;
- }
- /* ...but it's no longer valid */
- /* remove from hash, invalidate, and move to lru head */
- LIST_REMOVE(lp, lp_hash);
- lp->lp_valid = 0;
- TAILQ_REMOVE(&nfs_lock_pid_lru, lp, lp_lru);
- TAILQ_INSERT_HEAD(&nfs_lock_pid_lru, lp, lp_lru);
- lp = NULL;
- break;
- }
-
- /* if we didn't find it (valid), use any newly allocated one */
- if (!lp)
- lp = mlp;
-
- /* if we don't have an lp and we've been asked to add it */
- if ((error == ENOENT) && addflag && !lp) {
- /* scan lru list for invalid, stale entries to reuse/free */
- int lrucnt = 0;
- microuptime(&now);
- for (lplru = TAILQ_FIRST(&nfs_lock_pid_lru); lplru; lplru = lplru_next) {
- lplru_next = TAILQ_NEXT(lplru, lp_lru);
- if (lplru->lp_valid && (lplru->lp_time >= (now.tv_sec - 2))) {
- /*
- * If the oldest LRU entry is relatively new, then don't
- * bother scanning any further.
- */
- break;
- }
- /* remove entry from LRU, and check if it's still in use */
- TAILQ_REMOVE(&nfs_lock_pid_lru, lplru, lp_lru);
- if (!lplru->lp_valid || !(plru = proc_find(lplru->lp_pid)) ||
- timevalcmp(&lplru->lp_pid_start, &plru->p_start, !=)) {
- if (plru != PROC_NULL) {
- proc_rele(plru);
- plru = PROC_NULL;
- }
- /* no longer in use */
- LIST_REMOVE(lplru, lp_hash);
- if (!lp) {
- /* we'll reuse this one */
- lp = lplru;
- } else {
- /* queue it up for freeing */
- TAILQ_INSERT_HEAD(&nfs_lock_pid_free, lplru, lp_lru);
- }
- } else {
- /* still in use */
- if (plru != PROC_NULL) {
- proc_rele(plru);
- plru = PROC_NULL;
- }
- lplru->lp_time = now.tv_sec;
- TAILQ_INSERT_TAIL(&nfs_lock_pid_lru, lplru, lp_lru);
- }
- /* don't check too many entries at once */
- if (++lrucnt > 8)
- break;
- }
- if (!lp) {
- /* we need to allocate a new one */
- lck_mtx_unlock(nfs_lock_mutex);
- MALLOC(mlp, struct nfs_lock_pid *, sizeof(struct nfs_lock_pid),
- M_TEMP, M_WAITOK | M_ZERO);
- lck_mtx_lock(nfs_lock_mutex);
- if (mlp) /* make sure somebody hasn't already added this guy */
- goto loop;
- error = ENOMEM;
- }
- }
- if ((error == ENOENT) && addflag && lp) {
- /* (re)initialize nfs_lock_pid info */
- lp->lp_pid = pid;
- lp->lp_pid_start = p->p_start;
- /* insert pid in hash */
- LIST_INSERT_HEAD(NFS_LOCK_PID_HASH(lp->lp_pid), lp, lp_hash);
- lp->lp_valid = 1;
- lp->lp_time = now.tv_sec;
- TAILQ_INSERT_TAIL(&nfs_lock_pid_lru, lp, lp_lru);
- error = 0;
- }
-
- if ((mlp && (lp != mlp)) || TAILQ_FIRST(&nfs_lock_pid_free)) {
- lck_mtx_unlock(nfs_lock_mutex);
- if (mlp && (lp != mlp)) {
- /* we didn't need this one, so we can free it */
- FREE(mlp, M_TEMP);
- }
- /* free up any stale entries */
- while ((lp = TAILQ_FIRST(&nfs_lock_pid_free))) {
- TAILQ_REMOVE(&nfs_lock_pid_free, lp, lp_lru);
- FREE(lp, M_TEMP);
- }
- lck_mtx_lock(nfs_lock_mutex);
- }
-
- return (error);
-}
-