diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/fs/namei.c b/fs/namei.c index 14ab8d3f2f0c..5ba42c453e31 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1134,6 +1134,30 @@ static struct dentry *d_alloc_and_lookup(struct dentry *parent, | |||
1134 | } | 1134 | } |
1135 | 1135 | ||
1136 | /* | 1136 | /* |
1137 | * We already have a dentry, but require a lookup to be performed on the parent | ||
1138 | * directory to fill in d_inode. Returns the new dentry, or ERR_PTR on error. | ||
1139 | * parent->d_inode->i_mutex must be held. d_lookup must have verified that no | ||
1140 | * child exists while under i_mutex. | ||
1141 | */ | ||
1142 | static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentry, | ||
1143 | struct nameidata *nd) | ||
1144 | { | ||
1145 | struct inode *inode = parent->d_inode; | ||
1146 | struct dentry *old; | ||
1147 | |||
1148 | /* Don't create child dentry for a dead directory. */ | ||
1149 | if (unlikely(IS_DEADDIR(inode))) | ||
1150 | return ERR_PTR(-ENOENT); | ||
1151 | |||
1152 | old = inode->i_op->lookup(inode, dentry, nd); | ||
1153 | if (unlikely(old)) { | ||
1154 | dput(dentry); | ||
1155 | dentry = old; | ||
1156 | } | ||
1157 | return dentry; | ||
1158 | } | ||
1159 | |||
1160 | /* | ||
1137 | * It's more convoluted than I'd like it to be, but... it's still fairly | 1161 | * It's more convoluted than I'd like it to be, but... it's still fairly |
1138 | * small and for now I'd prefer to have fast path as straight as possible. | 1162 | * small and for now I'd prefer to have fast path as straight as possible. |
1139 | * It _is_ time-critical. | 1163 | * It _is_ time-critical. |
@@ -1172,6 +1196,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
1172 | goto unlazy; | 1196 | goto unlazy; |
1173 | } | 1197 | } |
1174 | } | 1198 | } |
1199 | if (unlikely(d_need_lookup(dentry))) | ||
1200 | goto unlazy; | ||
1175 | path->mnt = mnt; | 1201 | path->mnt = mnt; |
1176 | path->dentry = dentry; | 1202 | path->dentry = dentry; |
1177 | if (unlikely(!__follow_mount_rcu(nd, path, inode))) | 1203 | if (unlikely(!__follow_mount_rcu(nd, path, inode))) |
@@ -1186,6 +1212,10 @@ unlazy: | |||
1186 | dentry = __d_lookup(parent, name); | 1212 | dentry = __d_lookup(parent, name); |
1187 | } | 1213 | } |
1188 | 1214 | ||
1215 | if (dentry && unlikely(d_need_lookup(dentry))) { | ||
1216 | dput(dentry); | ||
1217 | dentry = NULL; | ||
1218 | } | ||
1189 | retry: | 1219 | retry: |
1190 | if (unlikely(!dentry)) { | 1220 | if (unlikely(!dentry)) { |
1191 | struct inode *dir = parent->d_inode; | 1221 | struct inode *dir = parent->d_inode; |
@@ -1202,6 +1232,15 @@ retry: | |||
1202 | /* known good */ | 1232 | /* known good */ |
1203 | need_reval = 0; | 1233 | need_reval = 0; |
1204 | status = 1; | 1234 | status = 1; |
1235 | } else if (unlikely(d_need_lookup(dentry))) { | ||
1236 | dentry = d_inode_lookup(parent, dentry, nd); | ||
1237 | if (IS_ERR(dentry)) { | ||
1238 | mutex_unlock(&dir->i_mutex); | ||
1239 | return PTR_ERR(dentry); | ||
1240 | } | ||
1241 | /* known good */ | ||
1242 | need_reval = 0; | ||
1243 | status = 1; | ||
1205 | } | 1244 | } |
1206 | mutex_unlock(&dir->i_mutex); | 1245 | mutex_unlock(&dir->i_mutex); |
1207 | } | 1246 | } |
@@ -1683,6 +1722,16 @@ static struct dentry *__lookup_hash(struct qstr *name, | |||
1683 | */ | 1722 | */ |
1684 | dentry = d_lookup(base, name); | 1723 | dentry = d_lookup(base, name); |
1685 | 1724 | ||
1725 | if (dentry && d_need_lookup(dentry)) { | ||
1726 | /* | ||
1727 | * __lookup_hash is called with the parent dir's i_mutex already | ||
1728 | * held, so we are good to go here. | ||
1729 | */ | ||
1730 | dentry = d_inode_lookup(base, dentry, nd); | ||
1731 | if (IS_ERR(dentry)) | ||
1732 | return dentry; | ||
1733 | } | ||
1734 | |||
1686 | if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) | 1735 | if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) |
1687 | dentry = do_revalidate(dentry, nd); | 1736 | dentry = do_revalidate(dentry, nd); |
1688 | 1737 | ||