diff options
author | kib <kib@FreeBSD.org> | 2009-09-06 11:46:51 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-09-06 11:46:51 +0000 |
commit | 2e1ddcb5660c34e607974e7c57f48441b634d984 (patch) | |
tree | e884d99acd1c1411919d65a14e1a268ee484d9c6 /sys | |
parent | 14578a32762c68f2642b1efa67688539a49d1042 (diff) | |
download | FreeBSD-src-2e1ddcb5660c34e607974e7c57f48441b634d984.zip FreeBSD-src-2e1ddcb5660c34e607974e7c57f48441b634d984.tar.gz |
The clear_remove() and clear_inodedeps() call vn_start_write(NULL, &mp,
V_NOWAIT) on the non-busied mount point. Unmount might free ufs-specific
mp data, causing ffs_vgetf() to access freed memory.
Busy mountpoint before dropping softdep lk.
Noted and reviewed by: tegge
Tested by: pho
MFC after: 1 week
Diffstat (limited to 'sys')
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 5f16280..4d652c1 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -5977,12 +5977,19 @@ clear_remove(td) if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) continue; FREE_LOCK(&lk); - if ((error = ffs_vgetf(mp, ino, LK_EXCLUSIVE, &vp, - FFSV_FORCEINSMQ))) { + + /* + * Let unmount clear deps + */ + error = vfs_busy(mp, MBF_NOWAIT); + if (error != 0) + goto finish_write; + error = ffs_vgetf(mp, ino, LK_EXCLUSIVE, &vp, + FFSV_FORCEINSMQ); + vfs_unbusy(mp); + if (error != 0) { softdep_error("clear_remove: vget", error); - vn_finished_write(mp); - ACQUIRE_LOCK(&lk); - return; + goto finish_write; } if ((error = ffs_syncvnode(vp, MNT_NOWAIT))) softdep_error("clear_remove: fsync", error); @@ -5991,6 +5998,7 @@ clear_remove(td) drain_output(vp); BO_UNLOCK(bo); vput(vp); + finish_write: vn_finished_write(mp); ACQUIRE_LOCK(&lk); return; @@ -6050,13 +6058,21 @@ clear_inodedeps(td) if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) continue; FREE_LOCK(&lk); + error = vfs_busy(mp, MBF_NOWAIT); /* Let unmount clear deps */ + if (error != 0) { + vn_finished_write(mp); + ACQUIRE_LOCK(&lk); + return; + } if ((error = ffs_vgetf(mp, ino, LK_EXCLUSIVE, &vp, FFSV_FORCEINSMQ)) != 0) { softdep_error("clear_inodedeps: vget", error); + vfs_unbusy(mp); vn_finished_write(mp); ACQUIRE_LOCK(&lk); return; } + vfs_unbusy(mp); if (ino == lastino) { if ((error = ffs_syncvnode(vp, MNT_WAIT))) softdep_error("clear_inodedeps: fsync1", error); |