diff options
| -rw-r--r-- | arch/ia64/kernel/perfmon.c | 15 | ||||
| -rw-r--r-- | fs/9p/vfs_inode.c | 15 | ||||
| -rw-r--r-- | fs/cachefiles/daemon.c | 32 | ||||
| -rw-r--r-- | fs/dcache.c | 188 | ||||
| -rw-r--r-- | fs/fs_struct.c | 7 | ||||
| -rw-r--r-- | fs/isofs/inode.c | 7 | ||||
| -rw-r--r-- | fs/namei.c | 15 | ||||
| -rw-r--r-- | fs/namespace.c | 6 | ||||
| -rw-r--r-- | fs/proc/base.c | 24 | ||||
| -rw-r--r-- | fs/sysv/super.c | 1 | ||||
| -rw-r--r-- | include/linux/dcache.h | 1 | ||||
| -rw-r--r-- | include/linux/fs_struct.h | 27 | ||||
| -rw-r--r-- | include/linux/mount.h | 1 | ||||
| -rw-r--r-- | include/linux/path.h | 5 | ||||
| -rw-r--r-- | kernel/auditsc.c | 9 |
15 files changed, 223 insertions, 130 deletions
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 744329072f33..cce050e85c73 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c | |||
| @@ -2191,8 +2191,15 @@ pfmfs_delete_dentry(struct dentry *dentry) | |||
| 2191 | return 1; | 2191 | return 1; |
| 2192 | } | 2192 | } |
| 2193 | 2193 | ||
| 2194 | static char *pfmfs_dname(struct dentry *dentry, char *buffer, int buflen) | ||
| 2195 | { | ||
| 2196 | return dynamic_dname(dentry, buffer, buflen, "pfm:[%lu]", | ||
| 2197 | dentry->d_inode->i_ino); | ||
| 2198 | } | ||
| 2199 | |||
| 2194 | static const struct dentry_operations pfmfs_dentry_operations = { | 2200 | static const struct dentry_operations pfmfs_dentry_operations = { |
| 2195 | .d_delete = pfmfs_delete_dentry, | 2201 | .d_delete = pfmfs_delete_dentry, |
| 2202 | .d_dname = pfmfs_dname, | ||
| 2196 | }; | 2203 | }; |
| 2197 | 2204 | ||
| 2198 | 2205 | ||
| @@ -2202,8 +2209,7 @@ pfm_alloc_file(pfm_context_t *ctx) | |||
| 2202 | struct file *file; | 2209 | struct file *file; |
| 2203 | struct inode *inode; | 2210 | struct inode *inode; |
| 2204 | struct path path; | 2211 | struct path path; |
| 2205 | char name[32]; | 2212 | struct qstr this = { .name = "" }; |
| 2206 | struct qstr this; | ||
| 2207 | 2213 | ||
| 2208 | /* | 2214 | /* |
| 2209 | * allocate a new inode | 2215 | * allocate a new inode |
| @@ -2218,11 +2224,6 @@ pfm_alloc_file(pfm_context_t *ctx) | |||
| 2218 | inode->i_uid = current_fsuid(); | 2224 | inode->i_uid = current_fsuid(); |
| 2219 | inode->i_gid = current_fsgid(); | 2225 | inode->i_gid = current_fsgid(); |
| 2220 | 2226 | ||
| 2221 | sprintf(name, "[%lu]", inode->i_ino); | ||
| 2222 | this.name = name; | ||
| 2223 | this.len = strlen(name); | ||
| 2224 | this.hash = inode->i_ino; | ||
| 2225 | |||
| 2226 | /* | 2227 | /* |
| 2227 | * allocate a new dcache entry | 2228 | * allocate a new dcache entry |
| 2228 | */ | 2229 | */ |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index d97c34a24f7a..c7c23eab9440 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
| @@ -1263,10 +1263,19 @@ static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) | |||
| 1263 | return PTR_ERR(fid); | 1263 | return PTR_ERR(fid); |
| 1264 | 1264 | ||
| 1265 | retval = p9_client_setattr(fid, &p9attr); | 1265 | retval = p9_client_setattr(fid, &p9attr); |
| 1266 | if (retval >= 0) | 1266 | if (retval < 0) |
| 1267 | retval = inode_setattr(dentry->d_inode, iattr); | 1267 | return retval; |
| 1268 | 1268 | ||
| 1269 | return retval; | 1269 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 1270 | iattr->ia_size != i_size_read(dentry->d_inode)) { | ||
| 1271 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); | ||
| 1272 | if (retval) | ||
| 1273 | return retval; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | setattr_copy(dentry->d_inode, iattr); | ||
| 1277 | mark_inode_dirty(dentry->d_inode); | ||
| 1278 | return 0; | ||
| 1270 | } | 1279 | } |
| 1271 | 1280 | ||
| 1272 | /** | 1281 | /** |
diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c index 24eb0d37241a..727caedcdd92 100644 --- a/fs/cachefiles/daemon.c +++ b/fs/cachefiles/daemon.c | |||
| @@ -552,8 +552,7 @@ static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args) | |||
| 552 | */ | 552 | */ |
| 553 | static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) | 553 | static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) |
| 554 | { | 554 | { |
| 555 | struct fs_struct *fs; | 555 | struct path path; |
| 556 | struct dentry *dir; | ||
| 557 | const struct cred *saved_cred; | 556 | const struct cred *saved_cred; |
| 558 | int ret; | 557 | int ret; |
| 559 | 558 | ||
| @@ -573,24 +572,21 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) | |||
| 573 | } | 572 | } |
| 574 | 573 | ||
| 575 | /* extract the directory dentry from the cwd */ | 574 | /* extract the directory dentry from the cwd */ |
| 576 | fs = current->fs; | 575 | get_fs_pwd(current->fs, &path); |
| 577 | read_lock(&fs->lock); | ||
| 578 | dir = dget(fs->pwd.dentry); | ||
| 579 | read_unlock(&fs->lock); | ||
| 580 | 576 | ||
| 581 | if (!S_ISDIR(dir->d_inode->i_mode)) | 577 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) |
| 582 | goto notdir; | 578 | goto notdir; |
| 583 | 579 | ||
| 584 | cachefiles_begin_secure(cache, &saved_cred); | 580 | cachefiles_begin_secure(cache, &saved_cred); |
| 585 | ret = cachefiles_cull(cache, dir, args); | 581 | ret = cachefiles_cull(cache, path.dentry, args); |
| 586 | cachefiles_end_secure(cache, saved_cred); | 582 | cachefiles_end_secure(cache, saved_cred); |
| 587 | 583 | ||
| 588 | dput(dir); | 584 | path_put(&path); |
| 589 | _leave(" = %d", ret); | 585 | _leave(" = %d", ret); |
| 590 | return ret; | 586 | return ret; |
| 591 | 587 | ||
| 592 | notdir: | 588 | notdir: |
| 593 | dput(dir); | 589 | path_put(&path); |
| 594 | kerror("cull command requires dirfd to be a directory"); | 590 | kerror("cull command requires dirfd to be a directory"); |
| 595 | return -ENOTDIR; | 591 | return -ENOTDIR; |
| 596 | 592 | ||
| @@ -628,8 +624,7 @@ inval: | |||
| 628 | */ | 624 | */ |
| 629 | static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) | 625 | static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) |
| 630 | { | 626 | { |
| 631 | struct fs_struct *fs; | 627 | struct path path; |
| 632 | struct dentry *dir; | ||
| 633 | const struct cred *saved_cred; | 628 | const struct cred *saved_cred; |
| 634 | int ret; | 629 | int ret; |
| 635 | 630 | ||
| @@ -649,24 +644,21 @@ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) | |||
| 649 | } | 644 | } |
| 650 | 645 | ||
| 651 | /* extract the directory dentry from the cwd */ | 646 | /* extract the directory dentry from the cwd */ |
| 652 | fs = current->fs; | 647 | get_fs_pwd(current->fs, &path); |
| 653 | read_lock(&fs->lock); | ||
| 654 | dir = dget(fs->pwd.dentry); | ||
| 655 | read_unlock(&fs->lock); | ||
| 656 | 648 | ||
| 657 | if (!S_ISDIR(dir->d_inode->i_mode)) | 649 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) |
| 658 | goto notdir; | 650 | goto notdir; |
| 659 | 651 | ||
| 660 | cachefiles_begin_secure(cache, &saved_cred); | 652 | cachefiles_begin_secure(cache, &saved_cred); |
| 661 | ret = cachefiles_check_in_use(cache, dir, args); | 653 | ret = cachefiles_check_in_use(cache, path.dentry, args); |
| 662 | cachefiles_end_secure(cache, saved_cred); | 654 | cachefiles_end_secure(cache, saved_cred); |
| 663 | 655 | ||
| 664 | dput(dir); | 656 | path_put(&path); |
| 665 | //_leave(" = %d", ret); | 657 | //_leave(" = %d", ret); |
| 666 | return ret; | 658 | return ret; |
| 667 | 659 | ||
| 668 | notdir: | 660 | notdir: |
| 669 | dput(dir); | 661 | path_put(&path); |
| 670 | kerror("inuse command requires dirfd to be a directory"); | 662 | kerror("inuse command requires dirfd to be a directory"); |
| 671 | return -ENOTDIR; | 663 | return -ENOTDIR; |
| 672 | 664 | ||
diff --git a/fs/dcache.c b/fs/dcache.c index 9f2c13417969..166d35d56868 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 | * |
| 1914 | * Convert a dentry into an ASCII path name. If the entry has been deleted | 1915 | * Caller holds the dcache_lock. |
| 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 | * | ||
| 1920 | * "buflen" should be positive. 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,28 +1940,88 @@ 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 | retval += 1; /* hit the slash */ | 1961 | /* |
| 1974 | if (prepend_name(&retval, &buflen, &dentry->d_name) != 0) | 1962 | * Filesystems needing to implement special "root names" |
| 1975 | goto Elong; | 1963 | * should do so with ->d_dname() |
| 1964 | */ | ||
| 1965 | if (IS_ROOT(dentry) && | ||
| 1966 | (dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) { | ||
| 1967 | WARN(1, "Root dentry has weird name <%.*s>\n", | ||
| 1968 | (int) dentry->d_name.len, dentry->d_name.name); | ||
| 1969 | } | ||
| 1976 | root->mnt = vfsmnt; | 1970 | root->mnt = vfsmnt; |
| 1977 | root->dentry = dentry; | 1971 | root->dentry = dentry; |
| 1978 | goto out; | 1972 | goto out; |
| 1973 | } | ||
| 1979 | 1974 | ||
| 1980 | Elong: | 1975 | /** |
| 1981 | retval = ERR_PTR(-ENAMETOOLONG); | 1976 | * __d_path - return the path of a dentry |
| 1982 | 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. | ||
| 1983 | * | ||
| 1984 | * Returns a pointer into the buffer or an error code if the | ||
| 1985 | * path was too long. | ||
| 1986 | * | ||
| 1987 | * "buflen" should be positive. Caller holds the dcache_lock. | ||
| 1988 | * | ||
| 1989 | * If path is not reachable from the supplied root, then the value of | ||
| 1990 | * root is changed (without modifying refcounts). | ||
| 1991 | */ | ||
| 1992 | char *__d_path(const struct path *path, struct path *root, | ||
| 1993 | char *buf, int buflen) | ||
| 1994 | { | ||
| 1995 | char *res = buf + buflen; | ||
| 1996 | int error; | ||
| 1997 | |||
| 1998 | prepend(&res, &buflen, "\0", 1); | ||
| 1999 | error = prepend_path(path, root, &res, &buflen); | ||
| 2000 | if (error) | ||
| 2001 | return ERR_PTR(error); | ||
| 2002 | |||
| 2003 | return res; | ||
| 2004 | } | ||
| 2005 | |||
| 2006 | /* | ||
| 2007 | * same as __d_path but appends "(deleted)" for unlinked files. | ||
| 2008 | */ | ||
| 2009 | static int path_with_deleted(const struct path *path, struct path *root, | ||
| 2010 | char **buf, int *buflen) | ||
| 2011 | { | ||
| 2012 | prepend(buf, buflen, "\0", 1); | ||
| 2013 | if (d_unlinked(path->dentry)) { | ||
| 2014 | int error = prepend(buf, buflen, " (deleted)", 10); | ||
| 2015 | if (error) | ||
| 2016 | return error; | ||
| 2017 | } | ||
| 2018 | |||
| 2019 | return prepend_path(path, root, buf, buflen); | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | static int prepend_unreachable(char **buffer, int *buflen) | ||
| 2023 | { | ||
| 2024 | return prepend(buffer, buflen, "(unreachable)", 13); | ||
| 1983 | } | 2025 | } |
| 1984 | 2026 | ||
| 1985 | /** | 2027 | /** |
| @@ -2000,9 +2042,10 @@ Elong: | |||
| 2000 | */ | 2042 | */ |
| 2001 | char *d_path(const struct path *path, char *buf, int buflen) | 2043 | char *d_path(const struct path *path, char *buf, int buflen) |
| 2002 | { | 2044 | { |
| 2003 | char *res; | 2045 | char *res = buf + buflen; |
| 2004 | struct path root; | 2046 | struct path root; |
| 2005 | struct path tmp; | 2047 | struct path tmp; |
| 2048 | int error; | ||
| 2006 | 2049 | ||
| 2007 | /* | 2050 | /* |
| 2008 | * We have various synthetic filesystems that never get mounted. On | 2051 | * We have various synthetic filesystems that never get mounted. On |
| @@ -2014,19 +2057,51 @@ char *d_path(const struct path *path, char *buf, int buflen) | |||
| 2014 | if (path->dentry->d_op && path->dentry->d_op->d_dname) | 2057 | if (path->dentry->d_op && path->dentry->d_op->d_dname) |
| 2015 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | 2058 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); |
| 2016 | 2059 | ||
| 2017 | read_lock(¤t->fs->lock); | 2060 | get_fs_root(current->fs, &root); |
| 2018 | root = current->fs->root; | ||
| 2019 | path_get(&root); | ||
| 2020 | read_unlock(¤t->fs->lock); | ||
| 2021 | spin_lock(&dcache_lock); | 2061 | spin_lock(&dcache_lock); |
| 2022 | tmp = root; | 2062 | tmp = root; |
| 2023 | res = __d_path(path, &tmp, buf, buflen); | 2063 | error = path_with_deleted(path, &tmp, &res, &buflen); |
| 2064 | if (error) | ||
| 2065 | res = ERR_PTR(error); | ||
| 2024 | spin_unlock(&dcache_lock); | 2066 | spin_unlock(&dcache_lock); |
| 2025 | path_put(&root); | 2067 | path_put(&root); |
| 2026 | return res; | 2068 | return res; |
| 2027 | } | 2069 | } |
| 2028 | EXPORT_SYMBOL(d_path); | 2070 | EXPORT_SYMBOL(d_path); |
| 2029 | 2071 | ||
| 2072 | /** | ||
| 2073 | * d_path_with_unreachable - return the path of a dentry | ||
| 2074 | * @path: path to report | ||
| 2075 | * @buf: buffer to return value in | ||
| 2076 | * @buflen: buffer length | ||
| 2077 | * | ||
| 2078 | * The difference from d_path() is that this prepends "(unreachable)" | ||
| 2079 | * to paths which are unreachable from the current process' root. | ||
| 2080 | */ | ||
| 2081 | char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) | ||
| 2082 | { | ||
| 2083 | char *res = buf + buflen; | ||
| 2084 | struct path root; | ||
| 2085 | struct path tmp; | ||
| 2086 | int error; | ||
| 2087 | |||
| 2088 | if (path->dentry->d_op && path->dentry->d_op->d_dname) | ||
| 2089 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | ||
| 2090 | |||
| 2091 | get_fs_root(current->fs, &root); | ||
| 2092 | spin_lock(&dcache_lock); | ||
| 2093 | tmp = root; | ||
| 2094 | error = path_with_deleted(path, &tmp, &res, &buflen); | ||
| 2095 | if (!error && !path_equal(&tmp, &root)) | ||
| 2096 | error = prepend_unreachable(&res, &buflen); | ||
| 2097 | spin_unlock(&dcache_lock); | ||
| 2098 | path_put(&root); | ||
| 2099 | if (error) | ||
| 2100 | res = ERR_PTR(error); | ||
| 2101 | |||
| 2102 | return res; | ||
| 2103 | } | ||
| 2104 | |||
| 2030 | /* | 2105 | /* |
| 2031 | * Helper function for dentry_operations.d_dname() members | 2106 | * Helper function for dentry_operations.d_dname() members |
| 2032 | */ | 2107 | */ |
| @@ -2129,27 +2204,30 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
| 2129 | if (!page) | 2204 | if (!page) |
| 2130 | return -ENOMEM; | 2205 | return -ENOMEM; |
| 2131 | 2206 | ||
| 2132 | read_lock(¤t->fs->lock); | 2207 | get_fs_root_and_pwd(current->fs, &root, &pwd); |
| 2133 | pwd = current->fs->pwd; | ||
| 2134 | path_get(&pwd); | ||
| 2135 | root = current->fs->root; | ||
| 2136 | path_get(&root); | ||
| 2137 | read_unlock(¤t->fs->lock); | ||
| 2138 | 2208 | ||
| 2139 | error = -ENOENT; | 2209 | error = -ENOENT; |
| 2140 | spin_lock(&dcache_lock); | 2210 | spin_lock(&dcache_lock); |
| 2141 | if (!d_unlinked(pwd.dentry)) { | 2211 | if (!d_unlinked(pwd.dentry)) { |
| 2142 | unsigned long len; | 2212 | unsigned long len; |
| 2143 | struct path tmp = root; | 2213 | struct path tmp = root; |
| 2144 | char * cwd; | 2214 | char *cwd = page + PAGE_SIZE; |
| 2215 | int buflen = PAGE_SIZE; | ||
| 2145 | 2216 | ||
| 2146 | cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE); | 2217 | prepend(&cwd, &buflen, "\0", 1); |
| 2218 | error = prepend_path(&pwd, &tmp, &cwd, &buflen); | ||
| 2147 | spin_unlock(&dcache_lock); | 2219 | spin_unlock(&dcache_lock); |
| 2148 | 2220 | ||
| 2149 | error = PTR_ERR(cwd); | 2221 | if (error) |
| 2150 | if (IS_ERR(cwd)) | ||
| 2151 | goto out; | 2222 | goto out; |
| 2152 | 2223 | ||
| 2224 | /* Unreachable from current root */ | ||
| 2225 | if (!path_equal(&tmp, &root)) { | ||
| 2226 | error = prepend_unreachable(&cwd, &buflen); | ||
| 2227 | if (error) | ||
| 2228 | goto out; | ||
| 2229 | } | ||
| 2230 | |||
| 2153 | error = -ERANGE; | 2231 | error = -ERANGE; |
| 2154 | len = PAGE_SIZE + page - cwd; | 2232 | len = PAGE_SIZE + page - cwd; |
| 2155 | if (len <= size) { | 2233 | if (len <= size) { |
diff --git a/fs/fs_struct.c b/fs/fs_struct.c index eee059052db5..1ee40eb9a2c0 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c | |||
| @@ -106,12 +106,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) | |||
| 106 | fs->in_exec = 0; | 106 | fs->in_exec = 0; |
| 107 | rwlock_init(&fs->lock); | 107 | rwlock_init(&fs->lock); |
| 108 | fs->umask = old->umask; | 108 | fs->umask = old->umask; |
| 109 | read_lock(&old->lock); | 109 | get_fs_root_and_pwd(old, &fs->root, &fs->pwd); |
| 110 | fs->root = old->root; | ||
| 111 | path_get(&old->root); | ||
| 112 | fs->pwd = old->pwd; | ||
| 113 | path_get(&old->pwd); | ||
| 114 | read_unlock(&old->lock); | ||
| 115 | } | 110 | } |
| 116 | return fs; | 111 | return fs; |
| 117 | } | 112 | } |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 6b4dcd4f2943..5a44811b5027 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
| @@ -722,7 +722,12 @@ root_found: | |||
| 722 | } | 722 | } |
| 723 | 723 | ||
| 724 | s->s_magic = ISOFS_SUPER_MAGIC; | 724 | s->s_magic = ISOFS_SUPER_MAGIC; |
| 725 | s->s_maxbytes = 0xffffffff; /* We can handle files up to 4 GB */ | 725 | |
| 726 | /* | ||
| 727 | * With multi-extent files, file size is only limited by the maximum | ||
| 728 | * size of a file system, which is 8 TB. | ||
| 729 | */ | ||
| 730 | s->s_maxbytes = 0x80000000000LL; | ||
| 726 | 731 | ||
| 727 | /* | 732 | /* |
| 728 | * The CDROM is read-only, has no nodes (devices) on it, and since | 733 | * The CDROM is read-only, has no nodes (devices) on it, and since |
diff --git a/fs/namei.c b/fs/namei.c index 13ff4abdbdca..17ea76bf2fbe 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -483,13 +483,8 @@ ok: | |||
| 483 | 483 | ||
| 484 | static __always_inline void set_root(struct nameidata *nd) | 484 | static __always_inline void set_root(struct nameidata *nd) |
| 485 | { | 485 | { |
| 486 | if (!nd->root.mnt) { | 486 | if (!nd->root.mnt) |
| 487 | struct fs_struct *fs = current->fs; | 487 | get_fs_root(current->fs, &nd->root); |
| 488 | read_lock(&fs->lock); | ||
| 489 | nd->root = fs->root; | ||
| 490 | path_get(&nd->root); | ||
| 491 | read_unlock(&fs->lock); | ||
| 492 | } | ||
| 493 | } | 488 | } |
| 494 | 489 | ||
| 495 | static int link_path_walk(const char *, struct nameidata *); | 490 | static int link_path_walk(const char *, struct nameidata *); |
| @@ -1015,11 +1010,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei | |||
| 1015 | nd->path = nd->root; | 1010 | nd->path = nd->root; |
| 1016 | path_get(&nd->root); | 1011 | path_get(&nd->root); |
| 1017 | } else if (dfd == AT_FDCWD) { | 1012 | } else if (dfd == AT_FDCWD) { |
| 1018 | struct fs_struct *fs = current->fs; | 1013 | get_fs_pwd(current->fs, &nd->path); |
| 1019 | read_lock(&fs->lock); | ||
| 1020 | nd->path = fs->pwd; | ||
| 1021 | path_get(&fs->pwd); | ||
| 1022 | read_unlock(&fs->lock); | ||
| 1023 | } else { | 1014 | } else { |
| 1024 | struct dentry *dentry; | 1015 | struct dentry *dentry; |
| 1025 | 1016 | ||
diff --git a/fs/namespace.c b/fs/namespace.c index 66c4f7e781cb..2e10cb19c5b0 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -788,7 +788,6 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) | |||
| 788 | { MNT_NOATIME, ",noatime" }, | 788 | { MNT_NOATIME, ",noatime" }, |
| 789 | { MNT_NODIRATIME, ",nodiratime" }, | 789 | { MNT_NODIRATIME, ",nodiratime" }, |
| 790 | { MNT_RELATIME, ",relatime" }, | 790 | { MNT_RELATIME, ",relatime" }, |
| 791 | { MNT_STRICTATIME, ",strictatime" }, | ||
| 792 | { 0, NULL } | 791 | { 0, NULL } |
| 793 | }; | 792 | }; |
| 794 | const struct proc_fs_info *fs_infop; | 793 | const struct proc_fs_info *fs_infop; |
| @@ -2213,10 +2212,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
| 2213 | goto out1; | 2212 | goto out1; |
| 2214 | } | 2213 | } |
| 2215 | 2214 | ||
| 2216 | read_lock(¤t->fs->lock); | 2215 | get_fs_root(current->fs, &root); |
| 2217 | root = current->fs->root; | ||
| 2218 | path_get(¤t->fs->root); | ||
| 2219 | read_unlock(¤t->fs->lock); | ||
| 2220 | down_write(&namespace_sem); | 2216 | down_write(&namespace_sem); |
| 2221 | mutex_lock(&old.dentry->d_inode->i_mutex); | 2217 | mutex_lock(&old.dentry->d_inode->i_mutex); |
| 2222 | error = -EINVAL; | 2218 | error = -EINVAL; |
diff --git a/fs/proc/base.c b/fs/proc/base.c index c806dfb24e08..a1c43e7c8a7b 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -149,18 +149,13 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, | |||
| 149 | return count; | 149 | return count; |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | static int get_fs_path(struct task_struct *task, struct path *path, bool root) | 152 | static int get_task_root(struct task_struct *task, struct path *root) |
| 153 | { | 153 | { |
| 154 | struct fs_struct *fs; | ||
| 155 | int result = -ENOENT; | 154 | int result = -ENOENT; |
| 156 | 155 | ||
| 157 | task_lock(task); | 156 | task_lock(task); |
| 158 | fs = task->fs; | 157 | if (task->fs) { |
| 159 | if (fs) { | 158 | get_fs_root(task->fs, root); |
| 160 | read_lock(&fs->lock); | ||
| 161 | *path = root ? fs->root : fs->pwd; | ||
| 162 | path_get(path); | ||
| 163 | read_unlock(&fs->lock); | ||
| 164 | result = 0; | 159 | result = 0; |
| 165 | } | 160 | } |
| 166 | task_unlock(task); | 161 | task_unlock(task); |
| @@ -173,7 +168,12 @@ static int proc_cwd_link(struct inode *inode, struct path *path) | |||
| 173 | int result = -ENOENT; | 168 | int result = -ENOENT; |
| 174 | 169 | ||
| 175 | if (task) { | 170 | if (task) { |
| 176 | result = get_fs_path(task, path, 0); | 171 | task_lock(task); |
| 172 | if (task->fs) { | ||
| 173 | get_fs_pwd(task->fs, path); | ||
| 174 | result = 0; | ||
| 175 | } | ||
| 176 | task_unlock(task); | ||
| 177 | put_task_struct(task); | 177 | put_task_struct(task); |
| 178 | } | 178 | } |
| 179 | return result; | 179 | return result; |
| @@ -185,7 +185,7 @@ static int proc_root_link(struct inode *inode, struct path *path) | |||
| 185 | int result = -ENOENT; | 185 | int result = -ENOENT; |
| 186 | 186 | ||
| 187 | if (task) { | 187 | if (task) { |
| 188 | result = get_fs_path(task, path, 1); | 188 | result = get_task_root(task, path); |
| 189 | put_task_struct(task); | 189 | put_task_struct(task); |
| 190 | } | 190 | } |
| 191 | return result; | 191 | return result; |
| @@ -597,7 +597,7 @@ static int mounts_open_common(struct inode *inode, struct file *file, | |||
| 597 | get_mnt_ns(ns); | 597 | get_mnt_ns(ns); |
| 598 | } | 598 | } |
| 599 | rcu_read_unlock(); | 599 | rcu_read_unlock(); |
| 600 | if (ns && get_fs_path(task, &root, 1) == 0) | 600 | if (ns && get_task_root(task, &root) == 0) |
| 601 | ret = 0; | 601 | ret = 0; |
| 602 | put_task_struct(task); | 602 | put_task_struct(task); |
| 603 | } | 603 | } |
| @@ -1526,7 +1526,7 @@ static int do_proc_readlink(struct path *path, char __user *buffer, int buflen) | |||
| 1526 | if (!tmp) | 1526 | if (!tmp) |
| 1527 | return -ENOMEM; | 1527 | return -ENOMEM; |
| 1528 | 1528 | ||
| 1529 | pathname = d_path(path, tmp, PAGE_SIZE); | 1529 | pathname = d_path_with_unreachable(path, tmp, PAGE_SIZE); |
| 1530 | len = PTR_ERR(pathname); | 1530 | len = PTR_ERR(pathname); |
| 1531 | if (IS_ERR(pathname)) | 1531 | if (IS_ERR(pathname)) |
| 1532 | goto out; | 1532 | goto out; |
diff --git a/fs/sysv/super.c b/fs/sysv/super.c index 85359a8df605..a0b0cda6927e 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/buffer_head.h> | 26 | #include <linux/buffer_head.h> |
| 27 | #include <linux/parser.h> | ||
| 28 | #include "sysv.h" | 27 | #include "sysv.h" |
| 29 | 28 | ||
| 30 | /* | 29 | /* |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index d23be0386e2d..6a4aea30aa09 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
| @@ -315,6 +315,7 @@ extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); | |||
| 315 | 315 | ||
| 316 | extern char *__d_path(const struct path *path, struct path *root, char *, int); | 316 | extern char *__d_path(const struct path *path, struct path *root, char *, int); |
| 317 | extern char *d_path(const struct path *, char *, int); | 317 | extern char *d_path(const struct path *, char *, int); |
| 318 | extern char *d_path_with_unreachable(const struct path *, char *, int); | ||
| 318 | extern char *__dentry_path(struct dentry *, char *, int); | 319 | extern char *__dentry_path(struct dentry *, char *, int); |
| 319 | extern char *dentry_path(struct dentry *, char *, int); | 320 | extern char *dentry_path(struct dentry *, char *, int); |
| 320 | 321 | ||
diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h index 78a05bfcd8eb..eca3d5202138 100644 --- a/include/linux/fs_struct.h +++ b/include/linux/fs_struct.h | |||
| @@ -21,4 +21,31 @@ extern void free_fs_struct(struct fs_struct *); | |||
| 21 | extern void daemonize_fs_struct(void); | 21 | extern void daemonize_fs_struct(void); |
| 22 | extern int unshare_fs_struct(void); | 22 | extern int unshare_fs_struct(void); |
| 23 | 23 | ||
| 24 | static inline void get_fs_root(struct fs_struct *fs, struct path *root) | ||
| 25 | { | ||
| 26 | read_lock(&fs->lock); | ||
| 27 | *root = fs->root; | ||
| 28 | path_get(root); | ||
| 29 | read_unlock(&fs->lock); | ||
| 30 | } | ||
| 31 | |||
| 32 | static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd) | ||
| 33 | { | ||
| 34 | read_lock(&fs->lock); | ||
| 35 | *pwd = fs->pwd; | ||
| 36 | path_get(pwd); | ||
| 37 | read_unlock(&fs->lock); | ||
| 38 | } | ||
| 39 | |||
| 40 | static inline void get_fs_root_and_pwd(struct fs_struct *fs, struct path *root, | ||
| 41 | struct path *pwd) | ||
| 42 | { | ||
| 43 | read_lock(&fs->lock); | ||
| 44 | *root = fs->root; | ||
| 45 | path_get(root); | ||
| 46 | *pwd = fs->pwd; | ||
| 47 | path_get(pwd); | ||
| 48 | read_unlock(&fs->lock); | ||
| 49 | } | ||
| 50 | |||
| 24 | #endif /* _LINUX_FS_STRUCT_H */ | 51 | #endif /* _LINUX_FS_STRUCT_H */ |
diff --git a/include/linux/mount.h b/include/linux/mount.h index 907210bd9f9c..5e7a59408dd4 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
| @@ -27,7 +27,6 @@ struct mnt_namespace; | |||
| 27 | #define MNT_NODIRATIME 0x10 | 27 | #define MNT_NODIRATIME 0x10 |
| 28 | #define MNT_RELATIME 0x20 | 28 | #define MNT_RELATIME 0x20 |
| 29 | #define MNT_READONLY 0x40 /* does the user want this to be r/o? */ | 29 | #define MNT_READONLY 0x40 /* does the user want this to be r/o? */ |
| 30 | #define MNT_STRICTATIME 0x80 | ||
| 31 | 30 | ||
| 32 | #define MNT_SHRINKABLE 0x100 | 31 | #define MNT_SHRINKABLE 0x100 |
| 33 | #define MNT_WRITE_HOLD 0x200 | 32 | #define MNT_WRITE_HOLD 0x200 |
diff --git a/include/linux/path.h b/include/linux/path.h index 915e0c382a51..edc98dec6266 100644 --- a/include/linux/path.h +++ b/include/linux/path.h | |||
| @@ -12,4 +12,9 @@ struct path { | |||
| 12 | extern void path_get(struct path *); | 12 | extern void path_get(struct path *); |
| 13 | extern void path_put(struct path *); | 13 | extern void path_put(struct path *); |
| 14 | 14 | ||
| 15 | static inline int path_equal(const struct path *path1, const struct path *path2) | ||
| 16 | { | ||
| 17 | return path1->mnt == path2->mnt && path1->dentry == path2->dentry; | ||
| 18 | } | ||
| 19 | |||
| 15 | #endif /* _LINUX_PATH_H */ | 20 | #endif /* _LINUX_PATH_H */ |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index b87a63beb66c..1b31c130d034 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -1835,13 +1835,8 @@ void __audit_getname(const char *name) | |||
| 1835 | context->names[context->name_count].ino = (unsigned long)-1; | 1835 | context->names[context->name_count].ino = (unsigned long)-1; |
| 1836 | context->names[context->name_count].osid = 0; | 1836 | context->names[context->name_count].osid = 0; |
| 1837 | ++context->name_count; | 1837 | ++context->name_count; |
| 1838 | if (!context->pwd.dentry) { | 1838 | if (!context->pwd.dentry) |
| 1839 | read_lock(¤t->fs->lock); | 1839 | get_fs_pwd(current->fs, &context->pwd); |
| 1840 | context->pwd = current->fs->pwd; | ||
| 1841 | path_get(¤t->fs->pwd); | ||
| 1842 | read_unlock(¤t->fs->lock); | ||
| 1843 | } | ||
| 1844 | |||
| 1845 | } | 1840 | } |
| 1846 | 1841 | ||
| 1847 | /* audit_putname - intercept a putname request | 1842 | /* audit_putname - intercept a putname request |
