vfs: add prepend_path() helper
Split off prepend_path() from __d_path(). This new helper takes an end-of-buffer pointer and buffer-length pointer just like the other prepend_* functions. Move the " (deleted)" postfix out to __d_path(). This patch doesn't change any functionality but paves the way for the following patches. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
98dc568bc2
Коммит
f2eb6575d5
138
fs/dcache.c
138
fs/dcache.c
|
@ -1904,6 +1904,74 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
|
|||
return prepend(buffer, buflen, name->name, name->len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend path string to a buffer
|
||||
*
|
||||
* @path: the dentry/vfsmount to report
|
||||
* @root: root vfsmnt/dentry (may be modified by this function)
|
||||
* @buffer: pointer to the end of the buffer
|
||||
* @buflen: pointer to buffer length
|
||||
*
|
||||
* Caller holds the dcache_lock.
|
||||
*
|
||||
* If path is not reachable from the supplied root, then the value of
|
||||
* root is changed (without modifying refcounts).
|
||||
*/
|
||||
static int prepend_path(const struct path *path, struct path *root,
|
||||
char **buffer, int *buflen)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct vfsmount *vfsmnt = path->mnt;
|
||||
bool slash = false;
|
||||
int error = 0;
|
||||
|
||||
spin_lock(&vfsmount_lock);
|
||||
while (dentry != root->dentry || vfsmnt != root->mnt) {
|
||||
struct dentry * parent;
|
||||
|
||||
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
||||
/* Global root? */
|
||||
if (vfsmnt->mnt_parent == vfsmnt) {
|
||||
goto global_root;
|
||||
}
|
||||
dentry = vfsmnt->mnt_mountpoint;
|
||||
vfsmnt = vfsmnt->mnt_parent;
|
||||
continue;
|
||||
}
|
||||
parent = dentry->d_parent;
|
||||
prefetch(parent);
|
||||
error = prepend_name(buffer, buflen, &dentry->d_name);
|
||||
if (!error)
|
||||
error = prepend(buffer, buflen, "/", 1);
|
||||
if (error)
|
||||
break;
|
||||
|
||||
slash = true;
|
||||
dentry = parent;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!error && !slash)
|
||||
error = prepend(buffer, buflen, "/", 1);
|
||||
|
||||
spin_unlock(&vfsmount_lock);
|
||||
return error;
|
||||
|
||||
global_root:
|
||||
/*
|
||||
* Filesystems needing to implement special "root names"
|
||||
* should do so with ->d_dname()
|
||||
*/
|
||||
if (IS_ROOT(dentry) &&
|
||||
(dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) {
|
||||
WARN(1, "Root dentry has weird name <%.*s>\n",
|
||||
(int) dentry->d_name.len, dentry->d_name.name);
|
||||
}
|
||||
root->mnt = vfsmnt;
|
||||
root->dentry = dentry;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
* __d_path - return the path of a dentry
|
||||
* @path: the dentry/vfsmount to report
|
||||
|
@ -1923,69 +1991,23 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
|
|||
* root is changed (without modifying refcounts).
|
||||
*/
|
||||
char *__d_path(const struct path *path, struct path *root,
|
||||
char *buffer, int buflen)
|
||||
char *buf, int buflen)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct vfsmount *vfsmnt = path->mnt;
|
||||
char *end = buffer + buflen;
|
||||
char *retval;
|
||||
char *res = buf + buflen;
|
||||
int error;
|
||||
|
||||
spin_lock(&vfsmount_lock);
|
||||
prepend(&end, &buflen, "\0", 1);
|
||||
if (d_unlinked(dentry) &&
|
||||
(prepend(&end, &buflen, " (deleted)", 10) != 0))
|
||||
goto Elong;
|
||||
|
||||
if (buflen < 1)
|
||||
goto Elong;
|
||||
/* Get '/' right */
|
||||
retval = end-1;
|
||||
*retval = '/';
|
||||
|
||||
for (;;) {
|
||||
struct dentry * parent;
|
||||
|
||||
if (dentry == root->dentry && vfsmnt == root->mnt)
|
||||
break;
|
||||
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
||||
/* Global root? */
|
||||
if (vfsmnt->mnt_parent == vfsmnt) {
|
||||
goto global_root;
|
||||
}
|
||||
dentry = vfsmnt->mnt_mountpoint;
|
||||
vfsmnt = vfsmnt->mnt_parent;
|
||||
continue;
|
||||
}
|
||||
parent = dentry->d_parent;
|
||||
prefetch(parent);
|
||||
if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
|
||||
(prepend(&end, &buflen, "/", 1) != 0))
|
||||
goto Elong;
|
||||
retval = end;
|
||||
dentry = parent;
|
||||
prepend(&res, &buflen, "\0", 1);
|
||||
if (d_unlinked(path->dentry)) {
|
||||
error = prepend(&res, &buflen, " (deleted)", 10);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&vfsmount_lock);
|
||||
return retval;
|
||||
error = prepend_path(path, root, &res, &buflen);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
|
||||
global_root:
|
||||
/*
|
||||
* Filesystems needing to implement special "root names"
|
||||
* should do so with ->d_dname()
|
||||
*/
|
||||
if (IS_ROOT(dentry) &&
|
||||
(dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) {
|
||||
WARN(1, "Root dentry has weird name <%.*s>\n",
|
||||
(int) dentry->d_name.len, dentry->d_name.name);
|
||||
}
|
||||
root->mnt = vfsmnt;
|
||||
root->dentry = dentry;
|
||||
goto out;
|
||||
|
||||
Elong:
|
||||
retval = ERR_PTR(-ENAMETOOLONG);
|
||||
goto out;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче