aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/dcache.c33
-rw-r--r--fs/internal.h1
-rw-r--r--fs/namespace.c11
3 files changed, 39 insertions, 6 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index ce5a7e6d84cd..761e31bacbc2 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1184,6 +1184,39 @@ int have_submounts(struct dentry *parent)
1184EXPORT_SYMBOL(have_submounts); 1184EXPORT_SYMBOL(have_submounts);
1185 1185
1186/* 1186/*
1187 * Called by mount code to set a mountpoint and check if the mountpoint is
1188 * reachable (e.g. NFS can unhash a directory dentry and then the complete
1189 * subtree can become unreachable).
1190 *
1191 * Only one of check_submounts_and_drop() and d_set_mounted() must succeed. For
1192 * this reason take rename_lock and d_lock on dentry and ancestors.
1193 */
1194int d_set_mounted(struct dentry *dentry)
1195{
1196 struct dentry *p;
1197 int ret = -ENOENT;
1198 write_seqlock(&rename_lock);
1199 for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) {
1200 /* Need exclusion wrt. check_submounts_and_drop() */
1201 spin_lock(&p->d_lock);
1202 if (unlikely(d_unhashed(p))) {
1203 spin_unlock(&p->d_lock);
1204 goto out;
1205 }
1206 spin_unlock(&p->d_lock);
1207 }
1208 spin_lock(&dentry->d_lock);
1209 if (!d_unlinked(dentry)) {
1210 dentry->d_flags |= DCACHE_MOUNTED;
1211 ret = 0;
1212 }
1213 spin_unlock(&dentry->d_lock);
1214out:
1215 write_sequnlock(&rename_lock);
1216 return ret;
1217}
1218
1219/*
1187 * Search the dentry child list of the specified parent, 1220 * Search the dentry child list of the specified parent,
1188 * and move any unused dentries to the end of the unused 1221 * and move any unused dentries to the end of the unused
1189 * list for prune_dcache(). We descend to the next level 1222 * list for prune_dcache(). We descend to the next level
diff --git a/fs/internal.h b/fs/internal.h
index 7c5f01cf619d..d20893795526 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -126,6 +126,7 @@ extern int invalidate_inodes(struct super_block *, bool);
126 * dcache.c 126 * dcache.c
127 */ 127 */
128extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); 128extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
129extern int d_set_mounted(struct dentry *dentry);
129 130
130/* 131/*
131 * read_write.c 132 * read_write.c
diff --git a/fs/namespace.c b/fs/namespace.c
index ad8ea9bc2518..5997887cc64a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -611,6 +611,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
611{ 611{
612 struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry); 612 struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry);
613 struct mountpoint *mp; 613 struct mountpoint *mp;
614 int ret;
614 615
615 list_for_each_entry(mp, chain, m_hash) { 616 list_for_each_entry(mp, chain, m_hash) {
616 if (mp->m_dentry == dentry) { 617 if (mp->m_dentry == dentry) {
@@ -626,14 +627,12 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
626 if (!mp) 627 if (!mp)
627 return ERR_PTR(-ENOMEM); 628 return ERR_PTR(-ENOMEM);
628 629
629 spin_lock(&dentry->d_lock); 630 ret = d_set_mounted(dentry);
630 if (d_unlinked(dentry)) { 631 if (ret) {
631 spin_unlock(&dentry->d_lock);
632 kfree(mp); 632 kfree(mp);
633 return ERR_PTR(-ENOENT); 633 return ERR_PTR(ret);
634 } 634 }
635 dentry->d_flags |= DCACHE_MOUNTED; 635
636 spin_unlock(&dentry->d_lock);
637 mp->m_dentry = dentry; 636 mp->m_dentry = dentry;
638 mp->m_count = 1; 637 mp->m_count = 1;
639 list_add(&mp->m_hash, chain); 638 list_add(&mp->m_hash, chain);