mirror of
https://github.com/opnsense/src.git
synced 2026-05-25 10:50:13 -04:00
ufs rename: ensure that the result of ufs_checkpath() is stable
ufs_rename() calls ufs_checkpath() to ensure that the target directory is not a child of the source. If not, rename would create a loop. For instance: source->X1->X2->target and if source moved under target, we get corrupted filesystem. Suppose that we initially have source->X1 .... and X2->target where X1 is not on path from root to X2. Then ufs_checkpath() accepts the inodes, but there is nothing preventing parallel rename of X2 to become under X1, after checkpath finished. Ensure stability of ufs_checkpath() result by taking a per-mount sx in ufs_rename right before ufs_checkpath() and till the end. Reviewed by: chs, mckusick Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks
This commit is contained in:
parent
2e2212b4f5
commit
8df4bc48c8
4 changed files with 19 additions and 3 deletions
|
|
@ -1151,6 +1151,7 @@ ffs_mountfs(odevvp, mp, td)
|
|||
else
|
||||
ump->um_check_blkno = NULL;
|
||||
mtx_init(UFS_MTX(ump), "FFS", "FFS Lock", MTX_DEF);
|
||||
sx_init(&ump->um_checkpath_lock, "uchpth");
|
||||
ffs_oldfscompat_read(fs, ump, fs->fs_sblockloc);
|
||||
fs->fs_ronly = ronly;
|
||||
fs->fs_active = NULL;
|
||||
|
|
@ -1318,8 +1319,9 @@ out:
|
|||
g_vfs_close(cp);
|
||||
g_topology_unlock();
|
||||
}
|
||||
if (ump) {
|
||||
if (ump != NULL) {
|
||||
mtx_destroy(UFS_MTX(ump));
|
||||
sx_destroy(&ump->um_checkpath_lock);
|
||||
if (mp->mnt_gjprovider != NULL) {
|
||||
free(mp->mnt_gjprovider, M_UFSMNT);
|
||||
mp->mnt_gjprovider = NULL;
|
||||
|
|
@ -1545,6 +1547,7 @@ ffs_unmount(mp, mntflags)
|
|||
vrele(ump->um_odevvp);
|
||||
dev_rel(ump->um_dev);
|
||||
mtx_destroy(UFS_MTX(ump));
|
||||
sx_destroy(&ump->um_checkpath_lock);
|
||||
if (mp->mnt_gjprovider != NULL) {
|
||||
free(mp->mnt_gjprovider, M_UFSMNT);
|
||||
mp->mnt_gjprovider = NULL;
|
||||
|
|
|
|||
|
|
@ -1450,6 +1450,8 @@ ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target,
|
|||
vp = tvp = ITOV(target);
|
||||
mp = vp->v_mount;
|
||||
*wait_ino = 0;
|
||||
sx_assert(&VFSTOUFS(mp)->um_checkpath_lock, SA_XLOCKED);
|
||||
|
||||
if (target->i_number == source_ino)
|
||||
return (EEXIST);
|
||||
if (target->i_number == parent_ino)
|
||||
|
|
|
|||
|
|
@ -1249,9 +1249,9 @@ ufs_rename(ap)
|
|||
struct mount *mp;
|
||||
ino_t ino;
|
||||
seqc_t fdvp_s, fvp_s, tdvp_s, tvp_s;
|
||||
bool want_seqc_end;
|
||||
bool checkpath_locked, want_seqc_end;
|
||||
|
||||
want_seqc_end = false;
|
||||
checkpath_locked = want_seqc_end = false;
|
||||
|
||||
#ifdef INVARIANTS
|
||||
if ((tcnp->cn_flags & HASBUF) == 0 ||
|
||||
|
|
@ -1453,6 +1453,9 @@ relock:
|
|||
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread);
|
||||
if (error)
|
||||
goto unlockout;
|
||||
|
||||
sx_xlock(&VFSTOUFS(mp)->um_checkpath_lock);
|
||||
checkpath_locked = true;
|
||||
error = ufs_checkpath(ino, fdp->i_number, tdp, tcnp->cn_cred,
|
||||
&ino);
|
||||
/*
|
||||
|
|
@ -1460,6 +1463,8 @@ relock:
|
|||
* everything else and VGET before restarting.
|
||||
*/
|
||||
if (ino) {
|
||||
sx_xunlock(&VFSTOUFS(mp)->um_checkpath_lock);
|
||||
checkpath_locked = false;
|
||||
VOP_UNLOCK(fdvp);
|
||||
VOP_UNLOCK(fvp);
|
||||
VOP_UNLOCK(tdvp);
|
||||
|
|
@ -1690,6 +1695,9 @@ unlockout:
|
|||
vn_seqc_write_end(fdvp);
|
||||
}
|
||||
|
||||
if (checkpath_locked)
|
||||
sx_xunlock(&VFSTOUFS(mp)->um_checkpath_lock);
|
||||
|
||||
vput(fdvp);
|
||||
vput(fvp);
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ LIST_HEAD(trimlist_hashhead, ffs_blkfree_trim_params);
|
|||
|
||||
#include <sys/_lock.h>
|
||||
#include <sys/_mutex.h>
|
||||
#include <sys/_sx.h>
|
||||
|
||||
/*
|
||||
* This structure describes the UFS specific mount structure data.
|
||||
|
|
@ -99,6 +100,8 @@ struct ufsmount {
|
|||
uint64_t um_maxsymlinklen; /* (c) max size of short
|
||||
symlink */
|
||||
struct mtx um_lock; /* (c) Protects ufsmount & fs */
|
||||
struct sx um_checkpath_lock; /* (c) Protects ufs_checkpath()
|
||||
result */
|
||||
pid_t um_fsckpid; /* (u) PID can do fsck sysctl */
|
||||
struct mount_softdeps *um_softdep; /* (c) softdep mgmt structure */
|
||||
struct vnode *um_quotas[MAXQUOTAS]; /* (q) pointer to quota files */
|
||||
|
|
|
|||
Loading…
Reference in a new issue