| 1394 | } |
| 1395 | |
| 1396 | int |
| 1397 | kern_unmount(struct thread *td, const char *path, int flags) |
| 1398 | { |
| 1399 | struct nameidata nd; |
| 1400 | struct mount *mp; |
| 1401 | char *pathbuf; |
| 1402 | int error, id0, id1; |
| 1403 | |
| 1404 | AUDIT_ARG_VALUE(flags); |
| 1405 | if (jailed(td->td_ucred) || usermount == 0) { |
| 1406 | error = priv_check(td, PRIV_VFS_UNMOUNT); |
| 1407 | if (error) |
| 1408 | return (error); |
| 1409 | } |
| 1410 | |
| 1411 | pathbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK); |
| 1412 | error = copyinstr(path, pathbuf, MNAMELEN, NULL); |
| 1413 | if (error) { |
| 1414 | free(pathbuf, M_TEMP); |
| 1415 | return (error); |
| 1416 | } |
| 1417 | if (flags & MNT_BYFSID) { |
| 1418 | AUDIT_ARG_TEXT(pathbuf); |
| 1419 | /* Decode the filesystem ID. */ |
| 1420 | if (sscanf(pathbuf, "FSID:%d:%d", &id0, &id1) != 2) { |
| 1421 | free(pathbuf, M_TEMP); |
| 1422 | return (EINVAL); |
| 1423 | } |
| 1424 | |
| 1425 | mtx_lock(&mountlist_mtx); |
| 1426 | TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { |
| 1427 | if (mp->mnt_stat.f_fsid.val[0] == id0 && |
| 1428 | mp->mnt_stat.f_fsid.val[1] == id1) { |
| 1429 | vfs_ref(mp); |
| 1430 | break; |
| 1431 | } |
| 1432 | } |
| 1433 | mtx_unlock(&mountlist_mtx); |
| 1434 | } else { |
| 1435 | /* |
| 1436 | * Try to find global path for path argument. |
| 1437 | */ |
| 1438 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, |
| 1439 | UIO_SYSSPACE, pathbuf, td); |
| 1440 | if (namei(&nd) == 0) { |
| 1441 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 1442 | error = vn_path_to_global_path(td, nd.ni_vp, pathbuf, |
| 1443 | MNAMELEN); |
| 1444 | if (error == 0) |
| 1445 | vput(nd.ni_vp); |
| 1446 | } |
| 1447 | mtx_lock(&mountlist_mtx); |
| 1448 | TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { |
| 1449 | if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0) { |
| 1450 | vfs_ref(mp); |
| 1451 | break; |
| 1452 | } |
| 1453 | } |
no test coverage detected