vfs: depessimize getfsstat when only the count is requested

This avoids relocking mountlist_mtx for each entry.
This commit is contained in:
Mateusz Guzik 2020-07-10 06:47:58 +00:00
parent 8c1f410c19
commit 6c69e69724

View File

@ -441,7 +441,46 @@ kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
tofree = sfsp = *buf = malloc(maxcount * sizeof(struct statfs),
M_STATFS, M_WAITOK);
}
count = 0;
/*
* If there is no target buffer they only want the count.
*
* This could be TAILQ_FOREACH but it is open-coded to match the original
* code below.
*/
if (sfsp == NULL) {
mtx_lock(&mountlist_mtx);
for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
if (prison_canseemount(td->td_ucred, mp) != 0) {
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
#ifdef MAC
if (mac_mount_check_stat(td->td_ucred, mp) != 0) {
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
#endif
count++;
nmp = TAILQ_NEXT(mp, mnt_list);
}
mtx_unlock(&mountlist_mtx);
*countp = count;
return (0);
}
/*
* They want the entire thing.
*
* Short-circuit the corner case of no room for anything, avoids
* relocking below.
*/
if (maxcount < 1) {
goto out;
}
mtx_lock(&mountlist_mtx);
for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
if (prison_canseemount(td->td_ucred, mp) != 0) {
@ -473,7 +512,6 @@ kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
continue;
}
}
if (sfsp != NULL && count < maxcount) {
sp = &mp->mnt_stat;
/*
* If MNT_NOWAIT is specified, do not refresh
@ -509,16 +547,19 @@ kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
}
}
sfsp++;
}
count++;
if (count == maxcount) {
vfs_unbusy(mp);
break;
}
mtx_lock(&mountlist_mtx);
nmp = TAILQ_NEXT(mp, mnt_list);
vfs_unbusy(mp);
}
mtx_unlock(&mountlist_mtx);
if (sfsp != NULL && count > maxcount)
*countp = maxcount;
else
out:
*countp = count;
return (0);
}