diff options
Diffstat (limited to 'fs/dcache.c')
| -rw-r--r-- | fs/dcache.c | 94 |
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 | */ |
| 1925 | char *__d_path(const struct path *path, struct path *root, | 1920 | static 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 | ||
| 1968 | out: | 1953 | out: |
| 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 | ||
| 1972 | global_root: | 1960 | global_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 | ||
| 1986 | Elong: | 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 | */ | ||
| 1993 | char *__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 | /** |
