* Lookup a mount point by filesystem identifier, busying it before * returning. * * To avoid congestion on mountlist_mtx, implement simple direct-mapped * cache for popular filesystem identifiers. The cache is lockess, using * the fact that struct mount's are never freed. In worst case we may * get pointer to unmounted or even different filesystem, so we have to * check what we got, and g
| 863 | * check what we got, and go slow way if so. |
| 864 | */ |
| 865 | struct mount * |
| 866 | vfs_busyfs(fsid_t *fsid) |
| 867 | { |
| 868 | #define FSID_CACHE_SIZE 256 |
| 869 | typedef struct mount * volatile vmp_t; |
| 870 | static vmp_t cache[FSID_CACHE_SIZE]; |
| 871 | struct mount *mp; |
| 872 | int error; |
| 873 | uint32_t hash; |
| 874 | |
| 875 | CTR2(KTR_VFS, "%s: fsid %p", __func__, fsid); |
| 876 | hash = fsid->val[0] ^ fsid->val[1]; |
| 877 | hash = (hash >> 16 ^ hash) & (FSID_CACHE_SIZE - 1); |
| 878 | mp = cache[hash]; |
| 879 | if (mp == NULL || fsidcmp(&mp->mnt_stat.f_fsid, fsid) != 0) |
| 880 | goto slow; |
| 881 | if (vfs_busy(mp, 0) != 0) { |
| 882 | cache[hash] = NULL; |
| 883 | goto slow; |
| 884 | } |
| 885 | if (fsidcmp(&mp->mnt_stat.f_fsid, fsid) == 0) |
| 886 | return (mp); |
| 887 | else |
| 888 | vfs_unbusy(mp); |
| 889 | |
| 890 | slow: |
| 891 | mtx_lock(&mountlist_mtx); |
| 892 | TAILQ_FOREACH(mp, &mountlist, mnt_list) { |
| 893 | if (fsidcmp(&mp->mnt_stat.f_fsid, fsid) == 0) { |
| 894 | error = vfs_busy(mp, MBF_MNTLSTLOCK); |
| 895 | if (error) { |
| 896 | cache[hash] = NULL; |
| 897 | mtx_unlock(&mountlist_mtx); |
| 898 | return (NULL); |
| 899 | } |
| 900 | cache[hash] = mp; |
| 901 | return (mp); |
| 902 | } |
| 903 | } |
| 904 | CTR2(KTR_VFS, "%s: lookup failed for %p id", __func__, fsid); |
| 905 | mtx_unlock(&mountlist_mtx); |
| 906 | return ((struct mount *) 0); |
| 907 | } |
| 908 | |
| 909 | /* |
| 910 | * Check if a user can access privileged mount options. |
no test coverage detected