* any extra contention...
*/
-static int link_path_walk(const char *name, struct nameidata *nd);
+static int __link_path_walk(const char *name, struct nameidata *nd);
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
struct fs_struct *fs = current->fs;
read_lock(&fs->lock);
- if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
- nd->path.mnt = mntget(fs->altrootmnt);
- nd->path.dentry = dget(fs->altroot);
+ if (fs->altroot.dentry && !(nd->flags & LOOKUP_NOALT)) {
+ nd->path = fs->altroot;
+ path_get(&fs->altroot);
read_unlock(&fs->lock);
if (__emul_lookup_dentry(name,nd))
return 0;
read_lock(&fs->lock);
}
- nd->path.mnt = mntget(fs->rootmnt);
- nd->path.dentry = dget(fs->root);
+ nd->path = fs->root;
+ path_get(&fs->root);
read_unlock(&fs->lock);
return 1;
}
+/*
+ * Wrapper to retry pathname resolution whenever the underlying
+ * file system returns an ESTALE.
+ *
+ * Retry the whole path once, forcing real lookup requests
+ * instead of relying on the dcache.
+ */
+static __always_inline int link_path_walk(const char *name, struct nameidata *nd)
+{
+ struct path save = nd->path;
+ int result;
+
+ /* make sure the stuff we saved doesn't go away */
+ dget(save.dentry);
+ mntget(save.mnt);
+
+ result = __link_path_walk(name, nd);
+ if (result == -ESTALE) {
+ /* nd->path had been dropped */
+ nd->path = save;
+ dget(nd->path.dentry);
+ mntget(nd->path.mnt);
+ nd->flags |= LOOKUP_REVAL;
+ result = __link_path_walk(name, nd);
+ }
+
+ path_put(&save);
+
+ return result;
+}
+
static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{
int res = 0;
struct dentry *old = nd->path.dentry;
read_lock(&fs->lock);
- if (nd->path.dentry == fs->root &&
- nd->path.mnt == fs->rootmnt) {
+ if (nd->path.dentry == fs->root.dentry &&
+ nd->path.mnt == fs->root.mnt) {
read_unlock(&fs->lock);
break;
}
return err;
}
-/*
- * Wrapper to retry pathname resolution whenever the underlying
- * file system returns an ESTALE.
- *
- * Retry the whole path once, forcing real lookup requests
- * instead of relying on the dcache.
- */
-static int link_path_walk(const char *name, struct nameidata *nd)
-{
- struct nameidata save = *nd;
- int result;
-
- /* make sure the stuff we saved doesn't go away */
- dget(save.path.dentry);
- mntget(save.path.mnt);
-
- result = __link_path_walk(name, nd);
- if (result == -ESTALE) {
- *nd = save;
- dget(nd->path.dentry);
- mntget(nd->path.mnt);
- nd->flags |= LOOKUP_REVAL;
- result = __link_path_walk(name, nd);
- }
-
- path_put(&save.path);
-
- return result;
-}
-
static int path_walk(const char *name, struct nameidata *nd)
{
current->total_link_count = 0;
*/
nd->last_type = LAST_ROOT;
read_lock(&fs->lock);
- nd->path.mnt = mntget(fs->rootmnt);
- nd->path.dentry = dget(fs->root);
+ nd->path = fs->root;
+ path_get(&fs->root);
read_unlock(&fs->lock);
if (path_walk(name, nd) == 0) {
if (nd->path.dentry->d_inode) {
{
char *emul = __emul_prefix();
struct nameidata nd;
- struct vfsmount *mnt = NULL, *oldmnt;
- struct dentry *dentry = NULL, *olddentry;
+ struct path path = {}, old_path;
int err;
struct fs_struct *fs = current->fs;
if (!emul)
goto set_it;
err = path_lookup(emul, LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_NOALT, &nd);
- if (!err) {
- mnt = nd.path.mnt;
- dentry = nd.path.dentry;
- }
+ if (!err)
+ path = nd.path;
set_it:
write_lock(&fs->lock);
- oldmnt = fs->altrootmnt;
- olddentry = fs->altroot;
- fs->altrootmnt = mnt;
- fs->altroot = dentry;
+ old_path = fs->altroot;
+ fs->altroot = path;
write_unlock(&fs->lock);
- if (olddentry) {
- dput(olddentry);
- mntput(oldmnt);
- }
+ if (old_path.dentry)
+ path_put(&old_path);
}
/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
if (*name=='/') {
read_lock(&fs->lock);
- if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
- nd->path.mnt = mntget(fs->altrootmnt);
- nd->path.dentry = dget(fs->altroot);
+ if (fs->altroot.dentry && !(nd->flags & LOOKUP_NOALT)) {
+ nd->path = fs->altroot;
+ path_get(&fs->altroot);
read_unlock(&fs->lock);
if (__emul_lookup_dentry(name,nd))
goto out; /* found in altroot */
read_lock(&fs->lock);
}
- nd->path.mnt = mntget(fs->rootmnt);
- nd->path.dentry = dget(fs->root);
+ nd->path = fs->root;
+ path_get(&fs->root);
read_unlock(&fs->lock);
} else if (dfd == AT_FDCWD) {
read_lock(&fs->lock);
- nd->path.mnt = mntget(fs->pwdmnt);
- nd->path.dentry = dget(fs->pwd);
+ nd->path = fs->pwd;
+ path_get(&fs->pwd);
read_unlock(&fs->lock);
} else {
struct dentry *dentry;
}
/**
- * lookup_one_len: filesystem helper to lookup single pathname component
+ * lookup_one_len - filesystem helper to lookup single pathname component
* @name: pathname component to lookup
* @base: base directory to lookup from
* @len: maximum length @len should be interpreted to
*
- * Note that this routine is purely a helper for filesystem useage and should
- * not be called by generic code. Also note that by using this function to
+ * Note that this routine is purely a helper for filesystem usage and should
+ * not be called by generic code. Also note that by using this function the
* nameidata argument is passed to the filesystem methods and a filesystem
* using this helper needs to be prepared for that.
*/