|
@@ -586,6 +586,21 @@ static inline void path_to_nameidata(const struct path *path,
|
|
|
nd->path.dentry = path->dentry;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Helper to directly jump to a known parsed path from ->follow_link,
|
|
|
+ * caller must have taken a reference to path beforehand.
|
|
|
+ */
|
|
|
+void nd_jump_link(struct nameidata *nd, struct path *path)
|
|
|
+{
|
|
|
+ path_put(&nd->path);
|
|
|
+
|
|
|
+ nd->path = *path;
|
|
|
+ nd->inode = nd->path.dentry->d_inode;
|
|
|
+ nd->flags |= LOOKUP_JUMPED;
|
|
|
+
|
|
|
+ BUG_ON(nd->inode->i_op->follow_link);
|
|
|
+}
|
|
|
+
|
|
|
static inline void put_link(struct nameidata *nd, struct path *link, void *cookie)
|
|
|
{
|
|
|
struct inode *inode = link->dentry->d_inode;
|
|
@@ -630,17 +645,9 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
|
|
|
s = nd_get_link(nd);
|
|
|
if (s) {
|
|
|
error = __vfs_follow_link(nd, s);
|
|
|
- } else if (nd->last_type == LAST_BIND) {
|
|
|
- nd->flags |= LOOKUP_JUMPED;
|
|
|
- nd->inode = nd->path.dentry->d_inode;
|
|
|
- if (nd->inode->i_op->follow_link) {
|
|
|
- /* stepped on a _really_ weird one */
|
|
|
- path_put(&nd->path);
|
|
|
- error = -ELOOP;
|
|
|
- }
|
|
|
+ if (unlikely(error))
|
|
|
+ put_link(nd, link, *p);
|
|
|
}
|
|
|
- if (unlikely(error))
|
|
|
- put_link(nd, link, *p);
|
|
|
|
|
|
return error;
|
|
|
|