aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2010-08-10 05:41:39 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-08-11 00:28:21 -0400
commitf2eb6575d5beba1e98d400463007d77555d1fc35 (patch)
treed7459d7d06014b432ef8594f4d2e6de4966fe372 /fs/dcache.c
parent98dc568bc2ebefe4c0cb315a7fb7eff8bbb43176 (diff)
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>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c94
1 files changed, 58 insertions, 36 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index f1809e6b9fda..d09d93819b4d 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1905,48 +1905,30 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
1905} 1905}
1906 1906
1907/** 1907/**
1908 * __d_path - return the path of a dentry 1908 * Prepend path string to a buffer
1909 *
1909 * @path: the dentry/vfsmount to report 1910 * @path: the dentry/vfsmount to report
1910 * @root: root vfsmnt/dentry (may be modified by this function) 1911 * @root: root vfsmnt/dentry (may be modified by this function)
1911 * @buffer: buffer to return value in 1912 * @buffer: pointer to the end of the buffer
1912 * @buflen: buffer length 1913 * @buflen: pointer to buffer length
1913 *
1914 * Convert a dentry into an ASCII path name. If the entry has been deleted
1915 * the string " (deleted)" is appended. Note that this is ambiguous.
1916 *
1917 * Returns a pointer into the buffer or an error code if the
1918 * path was too long.
1919 * 1914 *
1920 * "buflen" should be positive. Caller holds the dcache_lock. 1915 * Caller holds the dcache_lock.
1921 * 1916 *
1922 * If path is not reachable from the supplied root, then the value of 1917 * If path is not reachable from the supplied root, then the value of
1923 * root is changed (without modifying refcounts). 1918 * root is changed (without modifying refcounts).
1924 */ 1919 */
1925char *__d_path(const struct path *path, struct path *root, 1920static int prepend_path(const struct path *path, struct path *root,
1926 char *buffer, int buflen) 1921 char **buffer, int *buflen)
1927{ 1922{
1928 struct dentry *dentry = path->dentry; 1923 struct dentry *dentry = path->dentry;
1929 struct vfsmount *vfsmnt = path->mnt; 1924 struct vfsmount *vfsmnt = path->mnt;
1930 char *end = buffer + buflen; 1925 bool slash = false;
1931 char *retval; 1926 int error = 0;
1932 1927
1933 spin_lock(&vfsmount_lock); 1928 spin_lock(&vfsmount_lock);
1934 prepend(&end, &buflen, "\0", 1); 1929 while (dentry != root->dentry || vfsmnt != root->mnt) {
1935 if (d_unlinked(dentry) &&
1936 (prepend(&end, &buflen, " (deleted)", 10) != 0))
1937 goto Elong;
1938
1939 if (buflen < 1)
1940 goto Elong;
1941 /* Get '/' right */
1942 retval = end-1;
1943 *retval = '/';
1944
1945 for (;;) {
1946 struct dentry * parent; 1930 struct dentry * parent;
1947 1931
1948 if (dentry == root->dentry && vfsmnt == root->mnt)
1949 break;
1950 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { 1932 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1951 /* Global root? */ 1933 /* Global root? */
1952 if (vfsmnt->mnt_parent == vfsmnt) { 1934 if (vfsmnt->mnt_parent == vfsmnt) {
@@ -1958,16 +1940,22 @@ char *__d_path(const struct path *path, struct path *root,
1958 } 1940 }
1959 parent = dentry->d_parent; 1941 parent = dentry->d_parent;
1960 prefetch(parent); 1942 prefetch(parent);
1961 if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || 1943 error = prepend_name(buffer, buflen, &dentry->d_name);
1962 (prepend(&end, &buflen, "/", 1) != 0)) 1944 if (!error)
1963 goto Elong; 1945 error = prepend(buffer, buflen, "/", 1);
1964 retval = end; 1946 if (error)
1947 break;
1948
1949 slash = true;
1965 dentry = parent; 1950 dentry = parent;
1966 } 1951 }
1967 1952
1968out: 1953out:
1954 if (!error && !slash)
1955 error = prepend(buffer, buflen, "/", 1);
1956
1969 spin_unlock(&vfsmount_lock); 1957 spin_unlock(&vfsmount_lock);
1970 return retval; 1958 return error;
1971 1959
1972global_root: 1960global_root:
1973 /* 1961 /*
@@ -1982,10 +1970,44 @@ global_root:
1982 root->mnt = vfsmnt; 1970 root->mnt = vfsmnt;
1983 root->dentry = dentry; 1971 root->dentry = dentry;
1984 goto out; 1972 goto out;
1973}
1985 1974
1986Elong: 1975/**
1987 retval = ERR_PTR(-ENAMETOOLONG); 1976 * __d_path - return the path of a dentry
1988 goto out; 1977 * @path: the dentry/vfsmount to report
1978 * @root: root vfsmnt/dentry (may be modified by this function)
1979 * @buffer: buffer to return value in
1980 * @buflen: buffer length
1981 *
1982 * Convert a dentry into an ASCII path name. If the entry has been deleted
1983 * the string " (deleted)" is appended. Note that this is ambiguous.
1984 *
1985 * Returns a pointer into the buffer or an error code if the
1986 * path was too long.
1987 *
1988 * "buflen" should be positive. Caller holds the dcache_lock.
1989 *
1990 * If path is not reachable from the supplied root, then the value of
1991 * root is changed (without modifying refcounts).
1992 */
1993char *__d_path(const struct path *path, struct path *root,
1994 char *buf, int buflen)
1995{
1996 char *res = buf + buflen;
1997 int error;
1998
1999 prepend(&res, &buflen, "\0", 1);
2000 if (d_unlinked(path->dentry)) {
2001 error = prepend(&res, &buflen, " (deleted)", 10);
2002 if (error)
2003 return ERR_PTR(error);
2004 }
2005
2006 error = prepend_path(path, root, &res, &buflen);
2007 if (error)
2008 return ERR_PTR(error);
2009
2010 return res;
1989} 2011}
1990 2012
1991/** 2013/**