Changeset View
Changeset View
Standalone View
Standalone View
sys/ufs/ffs/ffs_softdep.c
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 615 Lines • ▼ Show 20 Lines | softdep_prerename(fdvp, fvp, tdvp, tvp) | ||||
struct vnode *tdvp; | struct vnode *tdvp; | ||||
struct vnode *tvp; | struct vnode *tvp; | ||||
{ | { | ||||
panic("softdep_prerename called"); | panic("softdep_prerename called"); | ||||
} | } | ||||
int | int | ||||
softdep_prelink(dvp, vp) | softdep_prelink(dvp, vp, cnp) | ||||
struct vnode *dvp; | struct vnode *dvp; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct componentname *cnp; | |||||
{ | { | ||||
panic("softdep_prelink called"); | panic("softdep_prelink called"); | ||||
} | } | ||||
#else | #else | ||||
FEATURE(softupdates, "FFS soft-updates support"); | FEATURE(softupdates, "FFS soft-updates support"); | ||||
▲ Show 20 Lines • Show All 2,581 Lines • ▼ Show 20 Lines | if (jblocks != NULL && jblocks->jb_suspended && | ||||
mp->mnt_susp_owner = curthread; | mp->mnt_susp_owner = curthread; | ||||
vfs_write_resume(mp, 0); | vfs_write_resume(mp, 0); | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
return (1); | return (1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | |||||
journal_check_space(ump) | |||||
struct ufsmount *ump; | |||||
{ | |||||
struct mount *mp; | |||||
LOCK_OWNED(ump); | |||||
if (journal_space(ump, 0) == 0) { | |||||
softdep_speedup(ump); | |||||
mp = UFSTOVFS(ump); | |||||
FREE_LOCK(ump); | |||||
VFS_SYNC(mp, MNT_NOWAIT); | |||||
ffs_sbupdate(ump, MNT_WAIT, 0); | |||||
ACQUIRE_LOCK(ump); | |||||
if (journal_space(ump, 1) == 0) | |||||
journal_suspend(ump); | |||||
} | |||||
} | |||||
/* | /* | ||||
* Called before any allocation function to be certain that there is | * Called before any allocation function to be certain that there is | ||||
* sufficient space in the journal prior to creating any new records. | * sufficient space in the journal prior to creating any new records. | ||||
* Since in the case of block allocation we may have multiple locked | * Since in the case of block allocation we may have multiple locked | ||||
* buffers at the time of the actual allocation we can not block | * buffers at the time of the actual allocation we can not block | ||||
* when the journal records are created. Doing so would create a deadlock | * when the journal records are created. Doing so would create a deadlock | ||||
* if any of these buffers needed to be flushed to reclaim space. Instead | * if any of these buffers needed to be flushed to reclaim space. Instead | ||||
* we require a sufficiently large amount of available space such that | * we require a sufficiently large amount of available space such that | ||||
Show All 34 Lines | softdep_prealloc(vp, waitok) | ||||
* Attempt to sync this vnode once to flush any journal | * Attempt to sync this vnode once to flush any journal | ||||
* work attached to it. | * work attached to it. | ||||
*/ | */ | ||||
if ((curthread->td_pflags & TDP_COWINPROGRESS) == 0) | if ((curthread->td_pflags & TDP_COWINPROGRESS) == 0) | ||||
ffs_syncvnode(vp, waitok, 0); | ffs_syncvnode(vp, waitok, 0); | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
process_removes(vp); | process_removes(vp); | ||||
process_truncates(vp); | process_truncates(vp); | ||||
if (journal_space(ump, 0) == 0) { | journal_check_space(ump); | ||||
softdep_speedup(ump); | |||||
if (journal_space(ump, 1) == 0) | |||||
journal_suspend(ump); | |||||
} | |||||
FREE_LOCK(ump); | FREE_LOCK(ump); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Try hard to sync all data and metadata for the vnode, and workitems | * Try hard to sync all data and metadata for the vnode, and workitems | ||||
* flushing which might conflict with the vnode lock. This is a | * flushing which might conflict with the vnode lock. This is a | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | if (tvp != fvp && tvp != NULL) { | ||||
VOP_UNLOCK(tvp); | VOP_UNLOCK(tvp); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
} | } | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
softdep_speedup(ump); | softdep_speedup(ump); | ||||
process_worklist_item(UFSTOVFS(ump), 2, LK_NOWAIT); | process_worklist_item(UFSTOVFS(ump), 2, LK_NOWAIT); | ||||
if (journal_space(ump, 0) == 0) { | journal_check_space(ump); | ||||
softdep_speedup(ump); | |||||
if (journal_space(ump, 1) == 0) | |||||
journal_suspend(ump); | |||||
} | |||||
FREE_LOCK(ump); | FREE_LOCK(ump); | ||||
return (ERELOOKUP); | return (ERELOOKUP); | ||||
} | } | ||||
/* | /* | ||||
* Before adjusting a link count on a vnode verify that we have sufficient | * Before adjusting a link count on a vnode verify that we have sufficient | ||||
* journal space. If not, process operations that depend on the currently | * journal space. If not, process operations that depend on the currently | ||||
* locked pair of vnodes to try to flush space as the syncer, buf daemon, | * locked pair of vnodes to try to flush space as the syncer, buf daemon, | ||||
* and softdep flush threads can not acquire these locks to reclaim space. | * and softdep flush threads can not acquire these locks to reclaim space. | ||||
* | * | ||||
* Returns 0 if all owned locks are still valid and were not dropped | * Returns 0 if all owned locks are still valid and were not dropped | ||||
* in the process, in other case it returns either an error from sync, | * in the process, in other case it returns either an error from sync, | ||||
* or ERELOOKUP if any of the locks were re-acquired. In the later | * or ERELOOKUP if any of the locks were re-acquired. In the later | ||||
* case, the state of the vnodes cannot be relied upon and our VFS | * case, the state of the vnodes cannot be relied upon and our VFS | ||||
* syscall must be restarted at top level from the lookup. | * syscall must be restarted at top level from the lookup. | ||||
*/ | */ | ||||
int | int | ||||
softdep_prelink(dvp, vp) | softdep_prelink(dvp, vp, cnp) | ||||
struct vnode *dvp; | struct vnode *dvp; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct componentname *cnp; | |||||
{ | { | ||||
struct ufsmount *ump; | struct ufsmount *ump; | ||||
struct nameidata *ndp; | |||||
ASSERT_VOP_ELOCKED(dvp, "prelink dvp"); | ASSERT_VOP_ELOCKED(dvp, "prelink dvp"); | ||||
if (vp != NULL) | if (vp != NULL) | ||||
ASSERT_VOP_ELOCKED(vp, "prelink vp"); | ASSERT_VOP_ELOCKED(vp, "prelink vp"); | ||||
ump = VFSTOUFS(dvp->v_mount); | ump = VFSTOUFS(dvp->v_mount); | ||||
/* | /* | ||||
* Nothing to do if we have sufficient journal space. We skip | * Nothing to do if we have sufficient journal space. We skip | ||||
* flushing when vp is a snapshot to avoid deadlock where | * flushing when vp is a snapshot to avoid deadlock where | ||||
* another thread is trying to update the inodeblock for dvp | * another thread is trying to update the inodeblock for dvp | ||||
* and is waiting on snaplk that vp holds. | * and is waiting on snaplk that vp holds. | ||||
*/ | */ | ||||
if (journal_space(ump, 0) || (vp != NULL && IS_SNAPSHOT(VTOI(vp)))) | if (journal_space(ump, 0) || (vp != NULL && IS_SNAPSHOT(VTOI(vp)))) | ||||
return (0); | return (0); | ||||
/* | |||||
markj: unionfs does not pass a full nameidata to VOP_MKDIR in unionfs_mkshadowdir(). There is a… | |||||
* Check if the journal space consumption can in theory be | |||||
* accounted on dvp and vp. If the vnodes metadata was not | |||||
* changed comparing with the previous round-trip into | |||||
* softdep_prelink(), as indicated by the seqc generation | |||||
Done Inline ActionsI think it is worth adding a comment explaining the problem solved by this check. markj: I think it is worth adding a comment explaining the problem solved by this check. | |||||
* recorded in the nameidata, then there is no point in | |||||
* starting the sync. | |||||
*/ | |||||
ndp = __containerof(cnp, struct nameidata, ni_cnd); | |||||
if (!seqc_in_modify(ndp->ni_dvp_seqc) && | |||||
vn_seqc_consistent(dvp, ndp->ni_dvp_seqc) && | |||||
(vp == NULL || (!seqc_in_modify(ndp->ni_vp_seqc) && | |||||
vn_seqc_consistent(vp, ndp->ni_vp_seqc)))) | |||||
return (0); | |||||
stat_journal_low++; | stat_journal_low++; | ||||
if (vp != NULL) { | if (vp != NULL) { | ||||
VOP_UNLOCK(dvp); | VOP_UNLOCK(dvp); | ||||
ffs_syncvnode(vp, MNT_NOWAIT, 0); | ffs_syncvnode(vp, MNT_NOWAIT, 0); | ||||
vn_lock_pair(dvp, false, vp, true); | vn_lock_pair(dvp, false, vp, true); | ||||
if (dvp->v_data == NULL) | if (dvp->v_data == NULL) | ||||
return (ERELOOKUP); | goto out; | ||||
} | } | ||||
if (vp != NULL) | if (vp != NULL) | ||||
VOP_UNLOCK(vp); | VOP_UNLOCK(vp); | ||||
ffs_syncvnode(dvp, MNT_WAIT, 0); | ffs_syncvnode(dvp, MNT_WAIT, 0); | ||||
VOP_UNLOCK(dvp); | |||||
/* Process vp before dvp as it may create .. removes. */ | /* Process vp before dvp as it may create .. removes. */ | ||||
if (vp != NULL) { | if (vp != NULL) { | ||||
VOP_UNLOCK(dvp); | |||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | ||||
if (vp->v_data == NULL) { | if (vp->v_data == NULL) { | ||||
vn_lock_pair(dvp, false, vp, true); | vn_lock_pair(dvp, false, vp, true); | ||||
return (ERELOOKUP); | goto out; | ||||
} | } | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
process_removes(vp); | process_removes(vp); | ||||
process_truncates(vp); | process_truncates(vp); | ||||
FREE_LOCK(ump); | FREE_LOCK(ump); | ||||
VOP_UNLOCK(vp); | VOP_UNLOCK(vp); | ||||
} | |||||
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); | ||||
if (dvp->v_data == NULL) { | if (dvp->v_data == NULL) { | ||||
vn_lock_pair(dvp, true, vp, false); | vn_lock_pair(dvp, true, vp, false); | ||||
return (ERELOOKUP); | goto out; | ||||
} | } | ||||
} | |||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
process_removes(dvp); | process_removes(dvp); | ||||
process_truncates(dvp); | process_truncates(dvp); | ||||
VOP_UNLOCK(dvp); | VOP_UNLOCK(dvp); | ||||
softdep_speedup(ump); | softdep_speedup(ump); | ||||
process_worklist_item(UFSTOVFS(ump), 2, LK_NOWAIT); | process_worklist_item(UFSTOVFS(ump), 2, LK_NOWAIT); | ||||
if (journal_space(ump, 0) == 0) { | journal_check_space(ump); | ||||
Done Inline ActionsI suggest that you add FREE_LOCK(ump); VFS_SYNC(mp, MNT_NOWAIT); ffs_sbupdate(ump, MNT_WAIT, 0); ACQUIRE_LOCK(ump); As I suggested in my comment this will likely clear the oldest entries in the journal which will avoid causing us to suspend the filesystem. Note that you you will need to save mp above. mckusick: I suggest that you add
```
FREE_LOCK(ump);
VFS_SYNC(mp… | |||||
softdep_speedup(ump); | |||||
if (journal_space(ump, 1) == 0) | |||||
journal_suspend(ump); | |||||
} | |||||
FREE_LOCK(ump); | FREE_LOCK(ump); | ||||
vn_lock_pair(dvp, false, vp, false); | vn_lock_pair(dvp, false, vp, false); | ||||
out: | |||||
ndp->ni_dvp_seqc = vn_seqc_read_any(dvp); | |||||
if (vp != NULL) | |||||
ndp->ni_vp_seqc = vn_seqc_read_any(vp); | |||||
return (ERELOOKUP); | return (ERELOOKUP); | ||||
} | } | ||||
static void | static void | ||||
jseg_write(ump, jseg, data) | jseg_write(ump, jseg, data) | ||||
struct ufsmount *ump; | struct ufsmount *ump; | ||||
struct jseg *jseg; | struct jseg *jseg; | ||||
uint8_t *data; | uint8_t *data; | ||||
▲ Show 20 Lines • Show All 11,722 Lines • Show Last 20 Lines |
unionfs does not pass a full nameidata to VOP_MKDIR in unionfs_mkshadowdir(). There is a similar problem with unionfs_mkwhiteout() and unionfs_vn_create_on_upper().