diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 1f24cd684c51..0a38ef8d7f00 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2606,7 +2606,7 @@ static void __d_move(struct dentry * dentry, struct dentry * target) dentry_lock_for_move(dentry, target); write_seqcount_begin(&dentry->d_seq); - write_seqcount_begin(&target->d_seq); + write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED); /* __d_drop does write_seqcount_barrier, but they're OK to nest. */ @@ -2738,7 +2738,7 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) dentry_lock_for_move(anon, dentry); write_seqcount_begin(&dentry->d_seq); - write_seqcount_begin(&anon->d_seq); + write_seqcount_begin_nested(&anon->d_seq, DENTRY_D_LOCK_NESTED); dparent = dentry->d_parent; @@ -2912,9 +2912,9 @@ static int prepend_path(const struct path *path, const struct path *root, char **buffer, int *buflen) { - struct dentry *dentry = path->dentry; - struct vfsmount *vfsmnt = path->mnt; - struct mount *mnt = real_mount(vfsmnt); + struct dentry *dentry; + struct vfsmount *vfsmnt; + struct mount *mnt; int error = 0; unsigned seq, m_seq = 0; char *bptr; @@ -2924,10 +2924,14 @@ static int prepend_path(const struct path *path, restart_mnt: read_seqbegin_or_lock(&mount_lock, &m_seq); seq = 0; + rcu_read_lock(); restart: bptr = *buffer; blen = *buflen; error = 0; + dentry = path->dentry; + vfsmnt = path->mnt; + mnt = real_mount(vfsmnt); read_seqbegin_or_lock(&rename_lock, &seq); while (dentry != root->dentry || vfsmnt != root->mnt) { struct dentry * parent; @@ -2971,6 +2975,9 @@ restart: goto restart; } done_seqretry(&rename_lock, seq); + + if (!(m_seq & 1)) + rcu_read_unlock(); if (need_seqretry(&mount_lock, m_seq)) { m_seq = 1; goto restart_mnt; |