Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F171089466
D59356.id185857.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D59356.id185857.diff
View Options
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -712,7 +712,8 @@
static int flush_pagedep_deps(struct vnode *, struct mount *,
struct diraddhd *, struct buf *);
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,
+ struct diradd *);
static int flush_inodedep_deps(struct vnode *, struct mount *, ino_t);
static int flush_deplist(struct allocdirectlst *, int, int *);
static int sync_cgs(struct mount *, int);
@@ -13210,13 +13211,16 @@
}
/*
- * Flush dependencies associated with an allocdirect block.
+ * Flush dependencies associated with an allocdirect block. The softdep
+ * lock must be held on entry and is released on return. The locked parent
+ * directory buffer keeps dap valid while the lock is dropped.
*/
static int
flush_newblk_dep(
struct vnode *vp,
struct mount *mp,
- ufs_lbn_t lbn)
+ ufs_lbn_t lbn,
+ struct diradd *dap)
{
struct newblk *newblk;
struct ufsmount *ump;
@@ -13233,14 +13237,23 @@
if (blkno == 0)
panic("flush_newblk_dep: Missing block");
ump = VFSTOUFS(mp);
- ACQUIRE_LOCK(ump);
+ LOCK_OWNED(ump);
+ KASSERT(dap->da_newinum == ip->i_number,
+ ("flush_newblk_dep: inode mismatch %ju != %ju",
+ (uintmax_t)dap->da_newinum, (uintmax_t)ip->i_number));
/*
* Loop until all dependencies related to this block are satisfied.
* We must be careful to restart after each sleep in case a write
* completes some part of this process for us.
*/
for (;;) {
- if (newblk_lookup(mp, blkno, 0, &newblk) == 0) {
+ /*
+ * The mkdir dependency may have completed while we dropped the
+ * lock. Its allocdirect may then have been freed, exposing an
+ * older dependency for a previous use of the same block number.
+ */
+ if ((dap->da_state & MKDIR_BODY) == 0 ||
+ newblk_lookup(mp, blkno, 0, &newblk) == 0) {
FREE_LOCK(ump);
break;
}
@@ -13328,9 +13341,19 @@
LIST_INIT(&unfinished);
ump = VFSTOUFS(mp);
+ vp = NULL;
LOCK_OWNED(ump);
restart:
while ((dap = LIST_FIRST(diraddhdp)) != NULL) {
+ /*
+ * Only retain a vnode while restarting the lookup of the same
+ * MKDIR_BODY dependency. Dropping it may change the dependency
+ * list, so restart again after vput().
+ */
+ if (vp != NULL &&
+ ((dap->da_state & (MKDIR_PARENT | MKDIR_BODY)) != MKDIR_BODY ||
+ VTOI(vp)->i_number != dap->da_newinum))
+ goto vput_restart;
/*
* Flush ourselves if this directory entry
* has a MKDIR_PARENT dependency.
@@ -13375,25 +13398,38 @@
TAILQ_FOREACH(inoref, &inodedep->id_inoreflst, if_deps) {
if ((inoref->if_state & (DEPCOMPLETE | GOINGAWAY))
== DEPCOMPLETE) {
+ if (vp != NULL)
+ goto vput_restart;
jwait(&inoref->if_list, MNT_WAIT);
goto restart;
}
}
if (dap->da_state & MKDIR_BODY) {
- FREE_LOCK(ump);
- error = get_parent_vp(pvp, mp, inum, locked_bp,
- diraddhdp, &unfinished, &vp);
- if (error != 0)
- break;
- error = flush_newblk_dep(vp, mp, 0);
+ if (vp == NULL) {
+ FREE_LOCK(ump);
+ error = get_parent_vp(pvp, mp, inum, locked_bp,
+ diraddhdp, &unfinished, &vp);
+ if (error != 0)
+ break;
+ ACQUIRE_LOCK(ump);
+ goto restart;
+ }
+ error = flush_newblk_dep(vp, mp, 0, dap);
/*
* If we still have the dependency we might need to
* update the vnode to sync the new link count to
* disk.
*/
- if (error == 0 && dap == LIST_FIRST(diraddhdp))
- error = ffs_update(vp, 1);
+ if (error == 0) {
+ ACQUIRE_LOCK(ump);
+ if (dap == LIST_FIRST(diraddhdp)) {
+ FREE_LOCK(ump);
+ error = ffs_update(vp, 1);
+ } else
+ FREE_LOCK(ump);
+ }
vput(vp);
+ vp = NULL;
if (error != 0)
break;
ACQUIRE_LOCK(ump);
@@ -13452,6 +13488,7 @@
break;
error = ffs_update(vp, 1);
vput(vp);
+ vp = NULL;
if (error)
break;
ACQUIRE_LOCK(ump);
@@ -13469,11 +13506,23 @@
}
if (error)
ACQUIRE_LOCK(ump);
+ if (vp != NULL) {
+ FREE_LOCK(ump);
+ vput(vp);
+ ACQUIRE_LOCK(ump);
+ }
while ((dap = LIST_FIRST(&unfinished)) != NULL) {
LIST_REMOVE(dap, da_pdlist);
LIST_INSERT_HEAD(diraddhdp, dap, da_pdlist);
}
return (error);
+
+vput_restart:
+ FREE_LOCK(ump);
+ vput(vp);
+ vp = NULL;
+ ACQUIRE_LOCK(ump);
+ goto restart;
}
/*
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Sep 9, 3:26 PM (3 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38353965
Default Alt Text
D59356.id185857.diff (4 KB)
Attached To
Mode
D59356: ffs: fix stale newblk lookup in flush_newblk_dep
Attached
Detach File
Event Timeline
Log In to Comment