Changeset 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 603 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
softdep_freework(wkhd) | softdep_freework(wkhd) | ||||
struct workhead *wkhd; | struct workhead *wkhd; | ||||
{ | { | ||||
panic("softdep_freework called"); | panic("softdep_freework called"); | ||||
} | } | ||||
int | |||||
softdep_prerename(fdvp, fvp, tdvp, tvp) | |||||
struct vnode *fdvp; | |||||
struct vnode *fvp; | |||||
struct vnode *tdvp; | |||||
struct vnode *tvp; | |||||
{ | |||||
panic("softdep_prerename called"); | |||||
} | |||||
void | |||||
softdep_prelink(dvp, vp, will_direnter) | |||||
mckusick: This is missing the third (int) parameter. | |||||
struct vnode *dvp; | |||||
struct vnode *vp; | |||||
int will_direnter; | |||||
{ | |||||
panic("softdep_prelink called"); | |||||
} | |||||
#else | #else | ||||
FEATURE(softupdates, "FFS soft-updates support"); | FEATURE(softupdates, "FFS soft-updates support"); | ||||
static SYSCTL_NODE(_debug, OID_AUTO, softdep, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | static SYSCTL_NODE(_debug, OID_AUTO, softdep, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | ||||
"soft updates stats"); | "soft updates stats"); | ||||
static SYSCTL_NODE(_debug_softdep, OID_AUTO, total, | static SYSCTL_NODE(_debug_softdep, OID_AUTO, total, | ||||
CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | ||||
▲ Show 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | |||||
static struct buf *getdirtybuf(struct buf *, struct rwlock *, int); | static struct buf *getdirtybuf(struct buf *, struct rwlock *, int); | ||||
static int check_inodedep_free(struct inodedep *); | static int check_inodedep_free(struct inodedep *); | ||||
static void clear_remove(struct mount *); | static void clear_remove(struct mount *); | ||||
static void clear_inodedeps(struct mount *); | static void clear_inodedeps(struct mount *); | ||||
static void unlinked_inodedep(struct mount *, struct inodedep *); | static void unlinked_inodedep(struct mount *, struct inodedep *); | ||||
static void clear_unlinked_inodedep(struct inodedep *); | static void clear_unlinked_inodedep(struct inodedep *); | ||||
static struct inodedep *first_unlinked_inodedep(struct ufsmount *); | static struct inodedep *first_unlinked_inodedep(struct ufsmount *); | ||||
static int flush_pagedep_deps(struct vnode *, struct mount *, | static int flush_pagedep_deps(struct vnode *, struct mount *, | ||||
struct diraddhd *); | struct diraddhd *, struct buf *); | ||||
static int free_pagedep(struct pagedep *); | static int free_pagedep(struct pagedep *); | ||||
static int flush_newblk_dep(struct vnode *, struct mount *, ufs_lbn_t); | static int flush_newblk_dep(struct vnode *, struct mount *, ufs_lbn_t); | ||||
static int flush_inodedep_deps(struct vnode *, struct mount *, ino_t); | static int flush_inodedep_deps(struct vnode *, struct mount *, ino_t); | ||||
static int flush_deplist(struct allocdirectlst *, int, int *); | static int flush_deplist(struct allocdirectlst *, int, int *); | ||||
static int sync_cgs(struct mount *, int); | static int sync_cgs(struct mount *, int); | ||||
static int handle_written_filepage(struct pagedep *, struct buf *, int); | static int handle_written_filepage(struct pagedep *, struct buf *, int); | ||||
static int handle_written_sbdep(struct sbdep *, struct buf *); | static int handle_written_sbdep(struct sbdep *, struct buf *); | ||||
static void initiate_write_sbdep(struct sbdep *); | static void initiate_write_sbdep(struct sbdep *); | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | |||||
static void softdep_flushjournal(struct mount *); | static void softdep_flushjournal(struct mount *); | ||||
static int softdep_speedup(struct ufsmount *); | static int softdep_speedup(struct ufsmount *); | ||||
static void worklist_speedup(struct mount *); | static void worklist_speedup(struct mount *); | ||||
static int journal_mount(struct mount *, struct fs *, struct ucred *); | static int journal_mount(struct mount *, struct fs *, struct ucred *); | ||||
static void journal_unmount(struct ufsmount *); | static void journal_unmount(struct ufsmount *); | ||||
static int journal_space(struct ufsmount *, int); | static int journal_space(struct ufsmount *, int); | ||||
static void journal_suspend(struct ufsmount *); | static void journal_suspend(struct ufsmount *); | ||||
static int journal_unsuspend(struct ufsmount *ump); | static int journal_unsuspend(struct ufsmount *ump); | ||||
static void softdep_prelink(struct vnode *, struct vnode *); | |||||
static void add_to_journal(struct worklist *); | static void add_to_journal(struct worklist *); | ||||
static void remove_from_journal(struct worklist *); | static void remove_from_journal(struct worklist *); | ||||
static bool softdep_excess_items(struct ufsmount *, int); | static bool softdep_excess_items(struct ufsmount *, int); | ||||
static void softdep_process_journal(struct mount *, struct worklist *, int); | static void softdep_process_journal(struct mount *, struct worklist *, int); | ||||
static struct jremref *newjremref(struct dirrem *, struct inode *, | static struct jremref *newjremref(struct dirrem *, struct inode *, | ||||
struct inode *ip, off_t, nlink_t); | struct inode *ip, off_t, nlink_t); | ||||
static struct jaddref *newjaddref(struct inode *, ino_t, off_t, int16_t, | static struct jaddref *newjaddref(struct inode *, ino_t, off_t, int16_t, | ||||
uint16_t); | uint16_t); | ||||
▲ Show 20 Lines • Show All 446 Lines • ▼ Show 20 Lines | |||||
SYSCTL_INT(_vfs_ffs, OID_AUTO, compute_summary_at_mount, CTLFLAG_RW, | SYSCTL_INT(_vfs_ffs, OID_AUTO, compute_summary_at_mount, CTLFLAG_RW, | ||||
&compute_summary_at_mount, 0, "Recompute summary at mount"); | &compute_summary_at_mount, 0, "Recompute summary at mount"); | ||||
static int print_threads = 0; | static int print_threads = 0; | ||||
SYSCTL_INT(_debug_softdep, OID_AUTO, print_threads, CTLFLAG_RW, | SYSCTL_INT(_debug_softdep, OID_AUTO, print_threads, CTLFLAG_RW, | ||||
&print_threads, 0, "Notify flusher thread start/stop"); | &print_threads, 0, "Notify flusher thread start/stop"); | ||||
/* List of all filesystems mounted with soft updates */ | /* List of all filesystems mounted with soft updates */ | ||||
static TAILQ_HEAD(, mount_softdeps) softdepmounts; | static TAILQ_HEAD(, mount_softdeps) softdepmounts; | ||||
/* | /* | ||||
* This function fetches inode inum on mount point mp. We already | |||||
* hold a locked vnode vp, and might have a locked buffer bp belonging | |||||
* to vp. | |||||
* We must not block on acquiring the new inode lock as we will get | |||||
* into a lock-order reversal with the buffer lock and possibly get a | |||||
* deadlock. Thus if we cannot instantiate the requested vnode | |||||
Done Inline ActionsI think it's supposed to be "Thus if" markj: I think it's supposed to be "Thus if" | |||||
* without sleeping on its lock, we must unlock the vnode and the | |||||
* buffer before doing a blocking on the vnode lock. We return | |||||
Done Inline Actions"before blocking on the vnode lock" markj: "before blocking on the vnode lock" | |||||
* ERELOOKUP if we have had to unlock either the vnode or the buffer so | |||||
* that the caller can reassess its state. | |||||
Done Inline Actionss/function/caller/ perhaps markj: s/function/caller/ perhaps | |||||
* | |||||
* Top-level VFS code (for syscalls and other consumers, e.g. callers | |||||
Done Inline ActionsWhy not break;? markj: Why not `break;`? | |||||
Done Inline ActionsNo point in checking for doomed. kib: No point in checking for doomed. | |||||
* of VOP_FSYNC() in syncer) check for ERELOOKUP and restart at safe | |||||
Done Inline ActionsDo we actually know that inum corresponds to a parent of vp? Can't it be the other way around? markj: Do we actually know that inum corresponds to a parent of vp? Can't it be the other way around? | |||||
Done Inline ActionsYes, this is the valid question and Peter' report most likely indicates that. I will update the review with the patch I sent to him. kib: Yes, this is the valid question and Peter' report most likely indicates that. I will update… | |||||
Done Inline ActionsShouldn't this parameter be pvp (pvp is the parameter whose mode we are checking)? mckusick: Shouldn't this parameter be pvp (pvp is the parameter whose mode we are checking)? | |||||
* point. | |||||
* | |||||
* Since callers expect to operate on fully constructed vnode, we also | |||||
* recheck v_data after relock, and return ENOENT if NULL. | |||||
* | |||||
* If unlocking bp, we must unroll dequeueing its unfinished | |||||
* dependencies, and clear scan flag, before unlocking. If unlocking | |||||
Done Inline ActionsWhy is the assertion only needed in the fallback case? I had to look up the log message for r356126 to understand the assertion. A KASSERT() with a message would be a bit nicer IMO, maybe "vnode %p has pending deactivation", assuming I understood correctly. markj: Why is the assertion only needed in the fallback case?
I had to look up the log message for… | |||||
* vp while it is under deactivation, we re-queue deactivation. | |||||
*/ | |||||
static int | |||||
get_parent_vp(struct vnode *vp, struct mount *mp, ino_t inum, struct buf *bp, | |||||
struct diraddhd *diraddhdp, struct diraddhd *unfinishedp, | |||||
struct vnode **rvp) | |||||
{ | |||||
struct vnode *pvp; | |||||
struct diradd *dap; | |||||
int error; | |||||
bool bplocked; | |||||
ASSERT_VOP_ELOCKED(vp, "child vnode must be locked"); | |||||
for (bplocked = true, pvp = NULL;;) { | |||||
error = ffs_vgetf(mp, inum, LK_EXCLUSIVE | LK_NOWAIT, &pvp, | |||||
FFSV_FORCEINSMQ); | |||||
if (error == 0) { | |||||
/* | |||||
* Since we could have unlocked vp, the inode | |||||
* number could no longer indicate a | |||||
* constructed node. In this case, we must | |||||
* restart the syscall. | |||||
*/ | |||||
if (VTOI(pvp)->i_mode == 0 || !bplocked) { | |||||
if (VTOI(pvp)->i_mode == 0) | |||||
vgone(pvp); | |||||
vput(pvp); | |||||
error = ERELOOKUP; | |||||
goto out; | |||||
} | |||||
error = 0; | |||||
goto out1; | |||||
} | |||||
if (bp != NULL && bplocked) { | |||||
/* | |||||
* Requeue unfinished dependencies before | |||||
* unlocking buffer, which could make | |||||
* diraddhdp invalid. | |||||
*/ | |||||
ACQUIRE_LOCK(VFSTOUFS(mp)); | |||||
while ((dap = LIST_FIRST(unfinishedp)) != NULL) { | |||||
LIST_REMOVE(dap, da_pdlist); | |||||
LIST_INSERT_HEAD(diraddhdp, dap, da_pdlist); | |||||
} | |||||
FREE_LOCK(VFSTOUFS(mp)); | |||||
bp->b_vflags &= ~BV_SCANNED; | |||||
BUF_NOREC(bp); | |||||
BUF_UNLOCK(bp); | |||||
bplocked = false; | |||||
} | |||||
/* | |||||
* Do not drop vnode lock while inactivating. This | |||||
* would result in leaks of the VI flags and | |||||
* reclaiming of non-truncated vnode. Instead, | |||||
* re-schedule inactivation hoping that we would be | |||||
* able to sync inode later. | |||||
*/ | |||||
if ((vp->v_iflag & VI_DOINGINACT) != 0) { | |||||
VI_LOCK(vp); | |||||
vp->v_iflag |= VI_OWEINACT; | |||||
VI_UNLOCK(vp); | |||||
return (ERELOOKUP); | |||||
} | |||||
VOP_UNLOCK(vp); | |||||
error = ffs_vgetf(mp, inum, LK_EXCLUSIVE, &pvp, | |||||
FFSV_FORCEINSMQ); | |||||
if (error != 0) { | |||||
MPASS(error != ERELOOKUP); | |||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | |||||
break; | |||||
} | |||||
if (VTOI(pvp)->i_mode == 0) { | |||||
vgone(pvp); | |||||
vput(pvp); | |||||
pvp = NULL; | |||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | |||||
error = ERELOOKUP; | |||||
break; | |||||
} | |||||
error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT); | |||||
if (error == 0) | |||||
break; | |||||
vput(pvp); | |||||
pvp = NULL; | |||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | |||||
if (vp->v_data == NULL) { | |||||
error = ENOENT; | |||||
break; | |||||
} | |||||
} | |||||
if (bp != NULL) { | |||||
MPASS(!bplocked); | |||||
error = ERELOOKUP; | |||||
} | |||||
if (error != 0 && pvp != NULL) { | |||||
vput(pvp); | |||||
pvp = NULL; | |||||
} | |||||
out1: | |||||
*rvp = pvp; | |||||
out: | |||||
ASSERT_VOP_ELOCKED(vp, "child vnode must be locked on return"); | |||||
return (error); | |||||
} | |||||
Done Inline ActionsThis function needs a comment. Here is a first cut assuming I understand its purpose: /* * This function fetches inode inum on mount point mp. As we * already hold a locked buffer, we must not block on acquiring * the new inode lock as we will get into a lock-order reversal * with the buffer lock and possibly get a deadlock. Thus we * must unlock the buffer before doing a blocking lock for the * inode. We return ERESTART if we have had to unlock the buffer * so that the function can reassess its state. */ mckusick: This function needs a comment. Here is a first cut assuming I understand its purpose:
```
/*
*… | |||||
/* | |||||
* This function cleans the worklist for a filesystem. | * This function cleans the worklist for a filesystem. | ||||
* Each filesystem running with soft dependencies gets its own | * Each filesystem running with soft dependencies gets its own | ||||
* thread to run in this function. The thread is started up in | * thread to run in this function. The thread is started up in | ||||
* softdep_mount and shutdown in softdep_unmount. They show up | * softdep_mount and shutdown in softdep_unmount. They show up | ||||
* as part of the kernel "bufdaemon" process whose process | * as part of the kernel "bufdaemon" process whose process | ||||
* entry is available in bufdaemonproc. | * entry is available in bufdaemonproc. | ||||
*/ | */ | ||||
static int searchfailed; | static int searchfailed; | ||||
▲ Show 20 Lines • Show All 1,688 Lines • ▼ Show 20 Lines | if (journal_space(ump, 0) == 0) { | ||||
softdep_speedup(ump); | softdep_speedup(ump); | ||||
if (journal_space(ump, 1) == 0) | if (journal_space(ump, 1) == 0) | ||||
journal_suspend(ump); | 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 | |||||
* flushing which might conflict with the vnode lock. This is a | |||||
* helper for softdep_prerename(). | |||||
*/ | |||||
static int | |||||
softdep_prerename_vnode(ump, vp) | |||||
Done Inline Actions"prehandle" is a pretty generic name. If it's supposed to be a softdep_prerename() helper, maybe softdep_prerename_vnode()? markj: "prehandle" is a pretty generic name. If it's supposed to be a softdep_prerename() helper… | |||||
Done Inline ActionsI considered to use it in softdep_prelink() as well, but not now. kib: I considered to use it in softdep_prelink() as well, but not now. | |||||
struct ufsmount *ump; | |||||
struct vnode *vp; | |||||
{ | |||||
int error; | |||||
ASSERT_VOP_ELOCKED(vp, "prehandle"); | |||||
if (vp->v_data == NULL) | |||||
return (0); | |||||
error = VOP_FSYNC(vp, MNT_WAIT, curthread); | |||||
if (error != 0) | |||||
return (error); | |||||
ACQUIRE_LOCK(ump); | |||||
process_removes(vp); | |||||
Done Inline ActionsIt would be useful to have a comment describing what this function does. Presumably similar to the one for the next function below (softdep_prelink()). mckusick: It would be useful to have a comment describing what this function does. Presumably similar to… | |||||
Done Inline ActionsI did it, and also updated comment for softdep_prelink() which now follows different protocol and must be called earlier in VOPs, before any mutation is done. But it is premature to document this work IMO, it is still not finished from the code PoV. Peter reported at least one more unfixed bug. kib: I did it, and also updated comment for softdep_prelink() which now follows different protocol… | |||||
process_truncates(vp); | |||||
FREE_LOCK(ump); | |||||
return (0); | |||||
} | |||||
/* | |||||
* Must be called from VOP_RENAME() after all vnodes are locked. | |||||
* Ensures that there is enough journal space for rename. It is | |||||
* sufficiently different from softdep_prelink() by having to handle | |||||
* four vnodes. | |||||
*/ | |||||
int | |||||
softdep_prerename(fdvp, fvp, tdvp, tvp) | |||||
struct vnode *fdvp; | |||||
struct vnode *fvp; | |||||
struct vnode *tdvp; | |||||
struct vnode *tvp; | |||||
{ | |||||
struct ufsmount *ump; | |||||
int error; | |||||
ump = VFSTOUFS(fdvp->v_mount); | |||||
if (journal_space(ump, 0)) | |||||
return (0); | |||||
VOP_UNLOCK(tdvp); | |||||
VOP_UNLOCK(fvp); | |||||
if (tvp != NULL && tvp != tdvp) | |||||
VOP_UNLOCK(tvp); | |||||
error = softdep_prerename_vnode(ump, fdvp); | |||||
VOP_UNLOCK(fdvp); | |||||
if (error != 0) | |||||
return (error); | |||||
VOP_LOCK(fvp, LK_EXCLUSIVE | LK_RETRY); | |||||
error = softdep_prerename_vnode(ump, fvp); | |||||
VOP_UNLOCK(fvp); | |||||
if (error != 0) | |||||
return (error); | |||||
if (tdvp != fdvp) { | |||||
VOP_LOCK(tdvp, LK_EXCLUSIVE | LK_RETRY); | |||||
error = softdep_prerename_vnode(ump, tdvp); | |||||
VOP_UNLOCK(tdvp); | |||||
if (error != 0) | |||||
return (error); | |||||
} | |||||
if (tvp != fvp && tvp != NULL) { | |||||
VOP_LOCK(tvp, LK_EXCLUSIVE | LK_RETRY); | |||||
error = softdep_prerename_vnode(ump, tvp); | |||||
VOP_UNLOCK(tvp); | |||||
if (error != 0) | |||||
return (error); | |||||
} | |||||
ACQUIRE_LOCK(ump); | |||||
softdep_speedup(ump); | |||||
process_worklist_item(UFSTOVFS(ump), 2, LK_NOWAIT); | |||||
if (journal_space(ump, 0) == 0) { | |||||
softdep_speedup(ump); | |||||
if (journal_space(ump, 1) == 0) | |||||
journal_suspend(ump); | |||||
} | |||||
FREE_LOCK(ump); | |||||
return (ERELOOKUP); | |||||
} | |||||
Done Inline ActionsIt would be useful to have a comment describing what this function does. mckusick: It would be useful to have a comment describing what this function does. | |||||
Done Inline ActionsThis is just a helper for softdep_prerename(). kib: This is just a helper for softdep_prerename(). | |||||
/* | |||||
* 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 | |||||
* 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 | |||||
* case, the state of the vnodes cannot be relied upon and our VFS | |||||
* syscall must be restarted at top level from the lookup. | |||||
*/ | */ | ||||
static void | int | ||||
softdep_prelink(dvp, vp) | softdep_prelink(dvp, vp, will_direnter) | ||||
struct vnode *dvp; | struct vnode *dvp; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
int will_direnter; | |||||
Done Inline ActionsIs it int on purpose? Some callers are using bool literals. markj: Is it `int` on purpose? Some callers are using bool literals. | |||||
Done Inline ActionsK&R definition + bool look strange to me. kib: K&R definition + bool look strange to me. | |||||
{ | { | ||||
struct ufsmount *ump; | struct ufsmount *ump; | ||||
int error, error1; | |||||
ASSERT_VOP_ELOCKED(dvp, "prelink dvp"); | |||||
if (vp != NULL) | |||||
ASSERT_VOP_ELOCKED(vp, "prelink vp"); | |||||
ump = VFSTOUFS(dvp->v_mount); | ump = VFSTOUFS(dvp->v_mount); | ||||
LOCK_OWNED(ump); | |||||
/* | /* | ||||
* Nothing to do if we have sufficient journal space. | * Nothing to do if we have sufficient journal space. | ||||
* If we currently hold the snapshot lock, we must avoid | * If we currently hold the snapshot lock, we must avoid | ||||
* handling other resources that could cause deadlock. | * handling other resources that could cause deadlock. | ||||
* | |||||
* will_direnter == 1: In case allocated a directory block in | |||||
* an indirect block, we must prevent holes in the directory | |||||
* created if directory entries are written out of order. To | |||||
* accomplish this we fsync when we extend a directory into | |||||
* indirects. During rename it's not safe to drop the tvp | |||||
* lock so sync must be delayed until it is. | |||||
* | |||||
* This synchronous step could be removed if fsck and the | |||||
* kernel were taught to fill in sparse directories rather | |||||
* than panic. | |||||
*/ | */ | ||||
if (journal_space(ump, 0) || (vp && IS_SNAPSHOT(VTOI(vp)))) | if (journal_space(ump, 0) || (vp != NULL && IS_SNAPSHOT(VTOI(vp)))) { | ||||
return; | error = 0; | ||||
if (will_direnter && (vp == NULL || !IS_SNAPSHOT(VTOI(vp)))) { | |||||
if (vp != NULL) | |||||
VOP_UNLOCK(vp); | |||||
error = ffs_syncvnode(dvp, MNT_WAIT, 0); | |||||
if (vp != NULL) { | |||||
error1 = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT); | |||||
if (error1 != 0) { | |||||
vn_lock_pair(dvp, true, vp, false); | |||||
if (error == 0) | |||||
error = ERELOOKUP; | |||||
} else if (vp->v_data == NULL) { | |||||
error = ERELOOKUP; | |||||
} | |||||
} | |||||
} | |||||
return (error); | |||||
} | |||||
stat_journal_low++; | stat_journal_low++; | ||||
FREE_LOCK(ump); | if (vp != NULL) { | ||||
if (vp) | VOP_UNLOCK(dvp); | ||||
ffs_syncvnode(vp, MNT_NOWAIT, 0); | ffs_syncvnode(vp, MNT_NOWAIT, 0); | ||||
vn_lock_pair(dvp, false, vp, true); | |||||
if (dvp->v_data == NULL) | |||||
return (ERELOOKUP); | |||||
} | |||||
if (vp != NULL) | |||||
VOP_UNLOCK(vp); | |||||
ffs_syncvnode(dvp, MNT_WAIT, 0); | ffs_syncvnode(dvp, MNT_WAIT, 0); | ||||
Done Inline ActionsThese three lines are the reason why the current patch does not work in +J case. Really, we cannot call ffs_syncvnode() this way. There are more issues in -J case as well, but I did not analyzed it completely. kib: These three lines are the reason why the current patch does not work in +J case. Really, we… | |||||
ACQUIRE_LOCK(ump); | VOP_UNLOCK(dvp); | ||||
/* Process vp before dvp as it may create .. removes. */ | /* Process vp before dvp as it may create .. removes. */ | ||||
if (vp) { | if (vp != NULL) { | ||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | |||||
if (vp->v_data == NULL) { | |||||
vn_lock_pair(dvp, false, vp, true); | |||||
return (ERELOOKUP); | |||||
} | |||||
ACQUIRE_LOCK(ump); | |||||
process_removes(vp); | process_removes(vp); | ||||
process_truncates(vp); | process_truncates(vp); | ||||
FREE_LOCK(ump); | |||||
VOP_UNLOCK(vp); | |||||
} | } | ||||
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); | |||||
if (dvp->v_data == NULL) { | |||||
vn_lock_pair(dvp, true, vp, false); | |||||
return (ERELOOKUP); | |||||
} | |||||
ACQUIRE_LOCK(ump); | |||||
process_removes(dvp); | process_removes(dvp); | ||||
process_truncates(dvp); | process_truncates(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) { | if (journal_space(ump, 0) == 0) { | ||||
softdep_speedup(ump); | softdep_speedup(ump); | ||||
if (journal_space(ump, 1) == 0) | if (journal_space(ump, 1) == 0) | ||||
journal_suspend(ump); | journal_suspend(ump); | ||||
} | } | ||||
FREE_LOCK(ump); | |||||
vn_lock_pair(dvp, false, vp, false); | |||||
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 1,589 Lines • ▼ Show 20 Lines | softdep_setup_create(dp, ip) | ||||
ACQUIRE_LOCK(ITOUMP(dp)); | ACQUIRE_LOCK(ITOUMP(dp)); | ||||
inodedep = inodedep_lookup_ip(ip); | inodedep = inodedep_lookup_ip(ip); | ||||
if (DOINGSUJ(dvp)) { | if (DOINGSUJ(dvp)) { | ||||
jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, | jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, | ||||
inoreflst); | inoreflst); | ||||
KASSERT(jaddref != NULL && jaddref->ja_parent == dp->i_number, | KASSERT(jaddref != NULL && jaddref->ja_parent == dp->i_number, | ||||
("softdep_setup_create: No addref structure present.")); | ("softdep_setup_create: No addref structure present.")); | ||||
} | } | ||||
softdep_prelink(dvp, NULL); | |||||
FREE_LOCK(ITOUMP(dp)); | FREE_LOCK(ITOUMP(dp)); | ||||
} | } | ||||
/* | /* | ||||
* Create a jaddref structure to track the addition of a DOTDOT link when | * Create a jaddref structure to track the addition of a DOTDOT link when | ||||
* we are reparenting an inode as part of a rename. This jaddref will be | * we are reparenting an inode as part of a rename. This jaddref will be | ||||
* found by softdep_setup_directory_change. Adjusts nlinkdelta for | * found by softdep_setup_directory_change. Adjusts nlinkdelta for | ||||
* non-journaling softdep. | * non-journaling softdep. | ||||
Show All 18 Lines | softdep_setup_dotdot_link(dp, ip) | ||||
if (DOINGSUJ(dvp)) | if (DOINGSUJ(dvp)) | ||||
jaddref = newjaddref(ip, dp->i_number, DOTDOT_OFFSET, | jaddref = newjaddref(ip, dp->i_number, DOTDOT_OFFSET, | ||||
dp->i_effnlink - 1, dp->i_mode); | dp->i_effnlink - 1, dp->i_mode); | ||||
ACQUIRE_LOCK(ITOUMP(dp)); | ACQUIRE_LOCK(ITOUMP(dp)); | ||||
inodedep = inodedep_lookup_ip(dp); | inodedep = inodedep_lookup_ip(dp); | ||||
if (jaddref) | if (jaddref) | ||||
TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, &jaddref->ja_ref, | TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, &jaddref->ja_ref, | ||||
if_deps); | if_deps); | ||||
softdep_prelink(dvp, ITOV(ip)); | |||||
FREE_LOCK(ITOUMP(dp)); | FREE_LOCK(ITOUMP(dp)); | ||||
} | } | ||||
/* | /* | ||||
* Create a jaddref structure to track a new link to an inode. The directory | * Create a jaddref structure to track a new link to an inode. The directory | ||||
* offset is not known until softdep_setup_directory_add or | * offset is not known until softdep_setup_directory_add or | ||||
* softdep_setup_directory_change. Adjusts nlinkdelta for non-journaling | * softdep_setup_directory_change. Adjusts nlinkdelta for non-journaling | ||||
* softdep. | * softdep. | ||||
Show All 14 Lines | softdep_setup_link(dp, ip) | ||||
if (DOINGSUJ(dvp)) | if (DOINGSUJ(dvp)) | ||||
jaddref = newjaddref(dp, ip->i_number, 0, ip->i_effnlink - 1, | jaddref = newjaddref(dp, ip->i_number, 0, ip->i_effnlink - 1, | ||||
ip->i_mode); | ip->i_mode); | ||||
ACQUIRE_LOCK(ITOUMP(dp)); | ACQUIRE_LOCK(ITOUMP(dp)); | ||||
inodedep = inodedep_lookup_ip(ip); | inodedep = inodedep_lookup_ip(ip); | ||||
if (jaddref) | if (jaddref) | ||||
TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, &jaddref->ja_ref, | TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, &jaddref->ja_ref, | ||||
if_deps); | if_deps); | ||||
softdep_prelink(dvp, ITOV(ip)); | |||||
FREE_LOCK(ITOUMP(dp)); | FREE_LOCK(ITOUMP(dp)); | ||||
} | } | ||||
/* | /* | ||||
* Called to create the jaddref structures to track . and .. references as | * Called to create the jaddref structures to track . and .. references as | ||||
* well as lookup and further initialize the incomplete jaddref created | * well as lookup and further initialize the incomplete jaddref created | ||||
* by softdep_setup_inomapdep when the inode was allocated. Adjusts | * by softdep_setup_inomapdep when the inode was allocated. Adjusts | ||||
* nlinkdelta for non-journaling softdep. | * nlinkdelta for non-journaling softdep. | ||||
Show All 33 Lines | KASSERT(jaddref->ja_parent == dp->i_number, | ||||
(uintmax_t)jaddref->ja_parent)); | (uintmax_t)jaddref->ja_parent)); | ||||
TAILQ_INSERT_BEFORE(&jaddref->ja_ref, &dotaddref->ja_ref, | TAILQ_INSERT_BEFORE(&jaddref->ja_ref, &dotaddref->ja_ref, | ||||
if_deps); | if_deps); | ||||
} | } | ||||
inodedep = inodedep_lookup_ip(dp); | inodedep = inodedep_lookup_ip(dp); | ||||
if (DOINGSUJ(dvp)) | if (DOINGSUJ(dvp)) | ||||
TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, | TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, | ||||
&dotdotaddref->ja_ref, if_deps); | &dotdotaddref->ja_ref, if_deps); | ||||
softdep_prelink(ITOV(dp), NULL); | |||||
FREE_LOCK(ITOUMP(dp)); | FREE_LOCK(ITOUMP(dp)); | ||||
} | } | ||||
/* | /* | ||||
* Called to track nlinkdelta of the inode and parent directories prior to | * Called to track nlinkdelta of the inode and parent directories prior to | ||||
* unlinking a directory. | * unlinking a directory. | ||||
*/ | */ | ||||
void | void | ||||
softdep_setup_rmdir(dp, ip) | softdep_setup_rmdir(dp, ip) | ||||
struct inode *dp; | struct inode *dp; | ||||
struct inode *ip; | struct inode *ip; | ||||
{ | { | ||||
struct vnode *dvp; | struct vnode *dvp; | ||||
KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, | KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, | ||||
("softdep_setup_rmdir called on non-softdep filesystem")); | ("softdep_setup_rmdir called on non-softdep filesystem")); | ||||
dvp = ITOV(dp); | dvp = ITOV(dp); | ||||
ACQUIRE_LOCK(ITOUMP(dp)); | ACQUIRE_LOCK(ITOUMP(dp)); | ||||
(void) inodedep_lookup_ip(ip); | (void) inodedep_lookup_ip(ip); | ||||
(void) inodedep_lookup_ip(dp); | (void) inodedep_lookup_ip(dp); | ||||
softdep_prelink(dvp, ITOV(ip)); | |||||
FREE_LOCK(ITOUMP(dp)); | FREE_LOCK(ITOUMP(dp)); | ||||
} | } | ||||
/* | /* | ||||
* Called to track nlinkdelta of the inode and parent directories prior to | * Called to track nlinkdelta of the inode and parent directories prior to | ||||
* unlink. | * unlink. | ||||
*/ | */ | ||||
void | void | ||||
softdep_setup_unlink(dp, ip) | softdep_setup_unlink(dp, ip) | ||||
struct inode *dp; | struct inode *dp; | ||||
struct inode *ip; | struct inode *ip; | ||||
{ | { | ||||
struct vnode *dvp; | struct vnode *dvp; | ||||
KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, | KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, | ||||
("softdep_setup_unlink called on non-softdep filesystem")); | ("softdep_setup_unlink called on non-softdep filesystem")); | ||||
dvp = ITOV(dp); | dvp = ITOV(dp); | ||||
ACQUIRE_LOCK(ITOUMP(dp)); | ACQUIRE_LOCK(ITOUMP(dp)); | ||||
(void) inodedep_lookup_ip(ip); | (void) inodedep_lookup_ip(ip); | ||||
(void) inodedep_lookup_ip(dp); | (void) inodedep_lookup_ip(dp); | ||||
softdep_prelink(dvp, ITOV(ip)); | |||||
FREE_LOCK(ITOUMP(dp)); | FREE_LOCK(ITOUMP(dp)); | ||||
} | } | ||||
/* | /* | ||||
* Called to release the journal structures created by a failed non-directory | * Called to release the journal structures created by a failed non-directory | ||||
* creation. Adjusts nlinkdelta for non-journaling softdep. | * creation. Adjusts nlinkdelta for non-journaling softdep. | ||||
*/ | */ | ||||
void | void | ||||
▲ Show 20 Lines • Show All 3,847 Lines • ▼ Show 20 Lines | softdep_change_directoryentry_offset(bp, dp, base, oldloc, newloc, entrysize) | ||||
/* | /* | ||||
* Moves are always journaled as it would be too complex to | * Moves are always journaled as it would be too complex to | ||||
* determine if any affected adds or removes are present in the | * determine if any affected adds or removes are present in the | ||||
* journal. | * journal. | ||||
*/ | */ | ||||
if (MOUNTEDSUJ(mp)) { | if (MOUNTEDSUJ(mp)) { | ||||
flags = DEPALLOC; | flags = DEPALLOC; | ||||
jmvref = newjmvref(dp, de->d_ino, | jmvref = newjmvref(dp, de->d_ino, | ||||
dp->i_offset + (oldloc - base), | I_OFFSET(dp) + (oldloc - base), | ||||
dp->i_offset + (newloc - base)); | I_OFFSET(dp) + (newloc - base)); | ||||
} | } | ||||
lbn = lblkno(ump->um_fs, dp->i_offset); | lbn = lblkno(ump->um_fs, I_OFFSET(dp)); | ||||
offset = blkoff(ump->um_fs, dp->i_offset); | offset = blkoff(ump->um_fs, I_OFFSET(dp)); | ||||
oldoffset = offset + (oldloc - base); | oldoffset = offset + (oldloc - base); | ||||
newoffset = offset + (newloc - base); | newoffset = offset + (newloc - base); | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
if (pagedep_lookup(mp, bp, dp->i_number, lbn, flags, &pagedep) == 0) | if (pagedep_lookup(mp, bp, dp->i_number, lbn, flags, &pagedep) == 0) | ||||
goto done; | goto done; | ||||
dap = diradd_lookup(pagedep, oldoffset); | dap = diradd_lookup(pagedep, oldoffset); | ||||
if (dap) { | if (dap) { | ||||
dap->da_offset = newoffset; | dap->da_offset = newoffset; | ||||
▲ Show 20 Lines • Show All 495 Lines • ▼ Show 20 Lines | newdirrem(bp, dp, ip, isrmdir, prevdirremp) | ||||
* dependencies. We will always have one for the link and | * dependencies. We will always have one for the link and | ||||
* when doing directories we will always have one more for dot. | * when doing directories we will always have one more for dot. | ||||
* When renaming a directory we skip the dotdot link change so | * When renaming a directory we skip the dotdot link change so | ||||
* this is not needed. | * this is not needed. | ||||
*/ | */ | ||||
jremref = dotremref = dotdotremref = NULL; | jremref = dotremref = dotdotremref = NULL; | ||||
if (DOINGSUJ(dvp)) { | if (DOINGSUJ(dvp)) { | ||||
if (isrmdir) { | if (isrmdir) { | ||||
jremref = newjremref(dirrem, dp, ip, dp->i_offset, | jremref = newjremref(dirrem, dp, ip, I_OFFSET(dp), | ||||
ip->i_effnlink + 2); | ip->i_effnlink + 2); | ||||
dotremref = newjremref(dirrem, ip, ip, DOT_OFFSET, | dotremref = newjremref(dirrem, ip, ip, DOT_OFFSET, | ||||
ip->i_effnlink + 1); | ip->i_effnlink + 1); | ||||
dotdotremref = newjremref(dirrem, ip, dp, DOTDOT_OFFSET, | dotdotremref = newjremref(dirrem, ip, dp, DOTDOT_OFFSET, | ||||
dp->i_effnlink + 1); | dp->i_effnlink + 1); | ||||
dotdotremref->jr_state |= MKDIR_PARENT; | dotdotremref->jr_state |= MKDIR_PARENT; | ||||
} else | } else | ||||
jremref = newjremref(dirrem, dp, ip, dp->i_offset, | jremref = newjremref(dirrem, dp, ip, I_OFFSET(dp), | ||||
ip->i_effnlink + 1); | ip->i_effnlink + 1); | ||||
} | } | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
lbn = lblkno(ump->um_fs, dp->i_offset); | lbn = lblkno(ump->um_fs, I_OFFSET(dp)); | ||||
offset = blkoff(ump->um_fs, dp->i_offset); | offset = blkoff(ump->um_fs, I_OFFSET(dp)); | ||||
pagedep_lookup(UFSTOVFS(ump), bp, dp->i_number, lbn, DEPALLOC, | pagedep_lookup(UFSTOVFS(ump), bp, dp->i_number, lbn, DEPALLOC, | ||||
&pagedep); | &pagedep); | ||||
dirrem->dm_pagedep = pagedep; | dirrem->dm_pagedep = pagedep; | ||||
dirrem->dm_offset = offset; | dirrem->dm_offset = offset; | ||||
/* | /* | ||||
* If we're renaming a .. link to a new directory, cancel any | * If we're renaming a .. link to a new directory, cancel any | ||||
* existing MKDIR_PARENT mkdir. If it has already been canceled | * existing MKDIR_PARENT mkdir. If it has already been canceled | ||||
* the jremref is preserved for any potential diradd in this | * the jremref is preserved for any potential diradd in this | ||||
* location. This can not coincide with a rmdir. | * location. This can not coincide with a rmdir. | ||||
*/ | */ | ||||
if (dp->i_offset == DOTDOT_OFFSET) { | if (I_OFFSET(dp) == DOTDOT_OFFSET) { | ||||
if (isrmdir) | if (isrmdir) | ||||
panic("newdirrem: .. directory change during remove?"); | panic("newdirrem: .. directory change during remove?"); | ||||
jremref = cancel_mkdir_dotdot(dp, dirrem, jremref); | jremref = cancel_mkdir_dotdot(dp, dirrem, jremref); | ||||
} | } | ||||
/* | /* | ||||
* If we're removing a directory search for the .. dependency now and | * If we're removing a directory search for the .. dependency now and | ||||
* cancel it. Any pending journal work will be added to the dirrem | * cancel it. Any pending journal work will be added to the dirrem | ||||
* to be completed when the workitem remove completes. | * to be completed when the workitem remove completes. | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir) | ||||
struct pagedep *pagedep; | struct pagedep *pagedep; | ||||
struct inodedep *inodedep; | struct inodedep *inodedep; | ||||
struct jaddref *jaddref; | struct jaddref *jaddref; | ||||
struct mount *mp; | struct mount *mp; | ||||
struct ufsmount *ump; | struct ufsmount *ump; | ||||
mp = ITOVFS(dp); | mp = ITOVFS(dp); | ||||
ump = VFSTOUFS(mp); | ump = VFSTOUFS(mp); | ||||
offset = blkoff(ump->um_fs, dp->i_offset); | offset = blkoff(ump->um_fs, I_OFFSET(dp)); | ||||
KASSERT(MOUNTEDSOFTDEP(mp) != 0, | KASSERT(MOUNTEDSOFTDEP(mp) != 0, | ||||
("softdep_setup_directory_change called on non-softdep filesystem")); | ("softdep_setup_directory_change called on non-softdep filesystem")); | ||||
/* | /* | ||||
* Whiteouts do not need diradd dependencies. | * Whiteouts do not need diradd dependencies. | ||||
*/ | */ | ||||
if (newinum != UFS_WINO) { | if (newinum != UFS_WINO) { | ||||
dap = malloc(sizeof(struct diradd), | dap = malloc(sizeof(struct diradd), | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir) | ||||
*/ | */ | ||||
inodedep_lookup(mp, newinum, DEPALLOC, &inodedep); | inodedep_lookup(mp, newinum, DEPALLOC, &inodedep); | ||||
if (MOUNTEDSUJ(mp)) { | if (MOUNTEDSUJ(mp)) { | ||||
jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, | jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, | ||||
inoreflst); | inoreflst); | ||||
KASSERT(jaddref != NULL && jaddref->ja_parent == dp->i_number, | KASSERT(jaddref != NULL && jaddref->ja_parent == dp->i_number, | ||||
("softdep_setup_directory_change: bad jaddref %p", | ("softdep_setup_directory_change: bad jaddref %p", | ||||
jaddref)); | jaddref)); | ||||
jaddref->ja_diroff = dp->i_offset; | jaddref->ja_diroff = I_OFFSET(dp); | ||||
jaddref->ja_diradd = dap; | jaddref->ja_diradd = dap; | ||||
LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)], | LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)], | ||||
dap, da_pdlist); | dap, da_pdlist); | ||||
add_to_journal(&jaddref->ja_list); | add_to_journal(&jaddref->ja_list); | ||||
} else if ((inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE) { | } else if ((inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE) { | ||||
dap->da_state |= COMPLETE; | dap->da_state |= COMPLETE; | ||||
LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap, da_pdlist); | LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap, da_pdlist); | ||||
WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list); | WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list); | ||||
} else { | } else { | ||||
LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)], | LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)], | ||||
dap, da_pdlist); | dap, da_pdlist); | ||||
WORKLIST_INSERT(&inodedep->id_bufwait, &dap->da_list); | WORKLIST_INSERT(&inodedep->id_bufwait, &dap->da_list); | ||||
} | } | ||||
/* | /* | ||||
* If we're making a new name for a directory that has not been | * If we're making a new name for a directory that has not been | ||||
* committed when need to move the dot and dotdot references to | * committed when need to move the dot and dotdot references to | ||||
* this new name. | * this new name. | ||||
*/ | */ | ||||
if (inodedep->id_mkdiradd && dp->i_offset != DOTDOT_OFFSET) | if (inodedep->id_mkdiradd && I_OFFSET(dp) != DOTDOT_OFFSET) | ||||
merge_diradd(inodedep, dap); | merge_diradd(inodedep, dap); | ||||
FREE_LOCK(ump); | FREE_LOCK(ump); | ||||
} | } | ||||
/* | /* | ||||
* Called whenever the link count on an inode is changed. | * Called whenever the link count on an inode is changed. | ||||
* It creates an inode dependency so that the new reference(s) | * It creates an inode dependency so that the new reference(s) | ||||
* to the inode cannot be committed to disk until the updated | * to the inode cannot be committed to disk until the updated | ||||
▲ Show 20 Lines • Show All 3,078 Lines • ▼ Show 20 Lines | for (error = 0, flushparent = 0; ; ) { | ||||
* We prevent deadlock by always fetching inodes from the | * We prevent deadlock by always fetching inodes from the | ||||
* root, moving down the directory tree. Thus, when fetching | * root, moving down the directory tree. Thus, when fetching | ||||
* our parent directory, we first try to get the lock. If | * our parent directory, we first try to get the lock. If | ||||
* that fails, we must unlock ourselves before requesting | * that fails, we must unlock ourselves before requesting | ||||
* the lock on our parent. See the comment in ufs_lookup | * the lock on our parent. See the comment in ufs_lookup | ||||
* for details on possible races. | * for details on possible races. | ||||
*/ | */ | ||||
FREE_LOCK(ump); | FREE_LOCK(ump); | ||||
if (ffs_vgetf(mp, parentino, LK_NOWAIT | LK_EXCLUSIVE, &pvp, | error = get_parent_vp(vp, mp, parentino, NULL, NULL, NULL, | ||||
FFSV_FORCEINSMQ)) { | &pvp); | ||||
/* | if (error == ERELOOKUP) | ||||
* Unmount cannot proceed after unlock because | error = 0; | ||||
* caller must have called vn_start_write(). | |||||
*/ | |||||
VOP_UNLOCK(vp); | |||||
error = ffs_vgetf(mp, parentino, LK_EXCLUSIVE, | |||||
&pvp, FFSV_FORCEINSMQ); | |||||
MPASS(VTOI(pvp)->i_mode != 0); | |||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | |||||
if (VN_IS_DOOMED(vp)) { | |||||
if (error == 0) | |||||
vput(pvp); | |||||
error = ENOENT; | |||||
} | |||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
Done Inline ActionsWhy can't we just use vn_vget_ino() here? mckusick: Why can't we just use vn_vget_ino() here? | |||||
Done Inline ActionsNo, unfortunately not. Issue is that the recorded ino might be no longer the parent of the vp. The example which started this patch actually flips parent and child around. We have to assume that two nodes are unrelated and engage into the algorithm which never sleeps with either of vnode locked. kib: No, unfortunately not. Issue is that the recorded ino might be no longer the parent of the vp. | |||||
} | |||||
/* | /* | ||||
* All MKDIR_PARENT dependencies and all the NEWBLOCK pagedeps | * All MKDIR_PARENT dependencies and all the NEWBLOCK pagedeps | ||||
* that are contained in direct blocks will be resolved by | * that are contained in direct blocks will be resolved by | ||||
* doing a ffs_update. Pagedeps contained in indirect blocks | * doing a ffs_update. Pagedeps contained in indirect blocks | ||||
* may require a complete sync'ing of the directory. So, we | * may require a complete sync'ing of the directory. So, we | ||||
* try the cheap and fast ffs_update first, and if that fails, | * try the cheap and fast ffs_update first, and if that fails, | ||||
* then we do the slower ffs_syncvnode of the directory. | * then we do the slower ffs_syncvnode of the directory. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 307 Lines • ▼ Show 20 Lines | case D_PAGEDEP: | ||||
* and/or dependencies on the inodes of any | * and/or dependencies on the inodes of any | ||||
* recently allocated files. We walk its diradd | * recently allocated files. We walk its diradd | ||||
* lists pushing out the associated inode. | * lists pushing out the associated inode. | ||||
*/ | */ | ||||
pagedep = WK_PAGEDEP(wk); | pagedep = WK_PAGEDEP(wk); | ||||
for (i = 0; i < DAHASHSZ; i++) { | for (i = 0; i < DAHASHSZ; i++) { | ||||
if (LIST_FIRST(&pagedep->pd_diraddhd[i]) == 0) | if (LIST_FIRST(&pagedep->pd_diraddhd[i]) == 0) | ||||
continue; | continue; | ||||
if ((error = flush_pagedep_deps(vp, wk->wk_mp, | error = flush_pagedep_deps(vp, wk->wk_mp, | ||||
&pagedep->pd_diraddhd[i]))) { | &pagedep->pd_diraddhd[i], bp); | ||||
if (error != 0) { | |||||
if (error != ERELOOKUP) | |||||
BUF_NOREC(bp); | BUF_NOREC(bp); | ||||
goto out_unlock; | goto out_unlock; | ||||
} | } | ||||
} | } | ||||
BUF_NOREC(bp); | BUF_NOREC(bp); | ||||
continue; | continue; | ||||
case D_FREEWORK: | case D_FREEWORK: | ||||
case D_FREEDEP: | case D_FREEDEP: | ||||
▲ Show 20 Lines • Show All 217 Lines • ▼ Show 20 Lines | flush_newblk_dep(vp, mp, lbn) | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Eliminate a pagedep dependency by flushing out all its diradd dependencies. | * Eliminate a pagedep dependency by flushing out all its diradd dependencies. | ||||
*/ | */ | ||||
static int | static int | ||||
flush_pagedep_deps(pvp, mp, diraddhdp) | flush_pagedep_deps(pvp, mp, diraddhdp, locked_bp) | ||||
struct vnode *pvp; | struct vnode *pvp; | ||||
struct mount *mp; | struct mount *mp; | ||||
struct diraddhd *diraddhdp; | struct diraddhd *diraddhdp; | ||||
struct buf *locked_bp; | |||||
{ | { | ||||
struct inodedep *inodedep; | struct inodedep *inodedep; | ||||
struct inoref *inoref; | struct inoref *inoref; | ||||
struct ufsmount *ump; | struct ufsmount *ump; | ||||
struct diradd *dap; | struct diradd *dap; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
int error = 0; | int error = 0; | ||||
struct buf *bp; | struct buf *bp; | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | TAILQ_FOREACH(inoref, &inodedep->id_inoreflst, if_deps) { | ||||
if ((inoref->if_state & (DEPCOMPLETE | GOINGAWAY)) | if ((inoref->if_state & (DEPCOMPLETE | GOINGAWAY)) | ||||
== DEPCOMPLETE) { | == DEPCOMPLETE) { | ||||
jwait(&inoref->if_list, MNT_WAIT); | jwait(&inoref->if_list, MNT_WAIT); | ||||
goto restart; | goto restart; | ||||
} | } | ||||
} | } | ||||
if (dap->da_state & MKDIR_BODY) { | if (dap->da_state & MKDIR_BODY) { | ||||
FREE_LOCK(ump); | FREE_LOCK(ump); | ||||
if ((error = ffs_vgetf(mp, inum, LK_EXCLUSIVE, &vp, | error = get_parent_vp(pvp, mp, inum, locked_bp, | ||||
FFSV_FORCEINSMQ))) | diraddhdp, &unfinished, &vp); | ||||
if (error != 0) | |||||
break; | break; | ||||
MPASS(VTOI(vp)->i_mode != 0); | |||||
error = flush_newblk_dep(vp, mp, 0); | error = flush_newblk_dep(vp, mp, 0); | ||||
/* | /* | ||||
* If we still have the dependency we might need to | * If we still have the dependency we might need to | ||||
* update the vnode to sync the new link count to | * update the vnode to sync the new link count to | ||||
* disk. | * disk. | ||||
*/ | */ | ||||
if (error == 0 && dap == LIST_FIRST(diraddhdp)) | if (error == 0 && dap == LIST_FIRST(diraddhdp)) | ||||
error = ffs_update(vp, 1); | error = ffs_update(vp, 1); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | retry: | ||||
} | } | ||||
/* | /* | ||||
* If the inode is still sitting in a buffer waiting | * If the inode is still sitting in a buffer waiting | ||||
* to be written or waiting for the link count to be | * to be written or waiting for the link count to be | ||||
* adjusted update it here to flush it to disk. | * adjusted update it here to flush it to disk. | ||||
*/ | */ | ||||
if (dap == LIST_FIRST(diraddhdp)) { | if (dap == LIST_FIRST(diraddhdp)) { | ||||
FREE_LOCK(ump); | FREE_LOCK(ump); | ||||
if ((error = ffs_vgetf(mp, inum, LK_EXCLUSIVE, &vp, | error = get_parent_vp(pvp, mp, inum, locked_bp, | ||||
FFSV_FORCEINSMQ))) | diraddhdp, &unfinished, &vp); | ||||
if (error != 0) | |||||
break; | break; | ||||
MPASS(VTOI(vp)->i_mode != 0); | |||||
error = ffs_update(vp, 1); | error = ffs_update(vp, 1); | ||||
vput(vp); | vput(vp); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
ACQUIRE_LOCK(ump); | ACQUIRE_LOCK(ump); | ||||
} | } | ||||
/* | /* | ||||
* If we have failed to get rid of all the dependencies | * If we have failed to get rid of all the dependencies | ||||
▲ Show 20 Lines • Show All 1,464 Lines • Show Last 20 Lines |
This is missing the third (int) parameter.