History

Fix nasty ncpfs symlink handling bug.

This bug could cause oopses and page state corruption, because ncpfs used the generic page-cache symlink handlign functions. But those functions only work if the page cache is guaranteed to be "stable", ie a page that was installed when the symlink walk was started has to still be installed in the page cache at the end of the walk. We could have fixed ncpfs to not use the generic helper routines, but it is in many ways much cleaner to instead improve on the symlink walking helper routines so that they don't require that absolute stability. We do this by allowing "follow_link()" to return a error-pointer as a cookie, which is fed back to the cleanup "put_link()" routine. This also simplifies NFS symlink handling.

Linus Torvalds committed 21 years ago

Commit cc314ee1 parent 2fb1e3010 files · +54 −77Browse files

Unified · Split

10 files
  1. fs/autofs/symlink.c +3 −2
  2. fs/cifs/cifsfs.h +2 −2
  3. fs/cifs/link.c +3 −3
  4. fs/ext2/symlink.c +2 −2
  5. fs/ext3/symlink.c +2 −2
  6. fs/namei.c +21 −19
  7. fs/nfs/symlink.c +8 −29
  8. fs/sysfs/symlink.c +3 −3
  9. include/linux/fs.h +4 −4
  10. mm/shmem.c +6 −11
fs/autofs/symlink.c+3−2
@@ -12,11 +12,12 @@ · 11 unmodified lines
1212
1313 #include "autofs_i.h"
1414
15−static int autofs_follow_link(struct dentry *dentry, struct nameidata *nd)
15+/* Nothing to release.. */
16+static void *autofs_follow_link(struct dentry *dentry, struct nameidata *nd)
1617 {
1718 char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data;
1819 nd_set_link(nd, s);
19− return 0;
20+ return NULL;
2021 }
2122
2223 struct inode_operations autofs_symlink_inode_operations = {
fs/cifs/cifsfs.h+2−2
@@ -83,8 +83,8 @@ extern int cifs_dir_notify(struct file *, unsigned long arg); · 82 unmodified lines
8383 extern struct dentry_operations cifs_dentry_ops;
8484
8585 /* Functions related to symlinks */
86−extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
87−extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd);
86+extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
87+extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *);
8888 extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
8989 int buflen);
9090 extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
fs/cifs/link.c+3−3
@@ -92,7 +92,7 @@ cifs_hl_exit: · 91 unmodified lines
9292 return rc;
9393 }
9494
95−int
95+void *
9696 cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
9797 {
9898 struct inode *inode = direntry->d_inode;
@@ -148,7 +148,7 @@ out: · 49 unmodified lines
148148 out_no_free:
149149 FreeXid(xid);
150150 nd_set_link(nd, target_path);
151− return 0;
151+ return NULL; /* No cookie */
152152 }
153153
154154 int
@@ -330,7 +330,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) · 175 unmodified lines
330330 return rc;
331331 }
332332
333−void cifs_put_link(struct dentry *direntry, struct nameidata *nd)
333+void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
334334 {
335335 char *p = nd_get_link(nd);
336336 if (!IS_ERR(p))
fs/ext2/symlink.c+2−2
@@ -21,11 +21,11 @@ · 20 unmodified lines
2121 #include "xattr.h"
2222 #include <linux/namei.h>
2323
24−static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
24+static void *ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
2525 {
2626 struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
2727 nd_set_link(nd, (char *)ei->i_data);
28− return 0;
28+ return NULL;
2929 }
3030
3131 struct inode_operations ext2_symlink_inode_operations = {
fs/ext3/symlink.c+2−2
@@ -23,11 +23,11 @@ · 22 unmodified lines
2323 #include <linux/namei.h>
2424 #include "xattr.h"
2525
26−static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
26+static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
2727 {
2828 struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
2929 nd_set_link(nd, (char*)ei->i_data);
30− return 0;
30+ return NULL;
3131 }
3232
3333 struct inode_operations ext3_symlink_inode_operations = {
fs/namei.c+21−19
@@ -501,6 +501,7 @@ struct path { · 500 unmodified lines
501501 static inline int __do_follow_link(struct path *path, struct nameidata *nd)
502502 {
503503 int error;
504+ void *cookie;
504505 struct dentry *dentry = path->dentry;
505506
506507 touch_atime(path->mnt, dentry);
@@ -508,13 +509,15 @@ static inline int __do_follow_link(struct path *path, struct nameidata *nd) · 1 unmodified line
508509
509510 if (path->mnt == nd->mnt)
510511 mntget(path->mnt);
511− error = dentry->d_inode->i_op->follow_link(dentry, nd);
512− if (!error) {
512+ cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
513+ error = PTR_ERR(cookie);
514+ if (!IS_ERR(cookie)) {
513515 char *s = nd_get_link(nd);
516+ error = 0;
514517 if (s)
515518 error = __vfs_follow_link(nd, s);
516519 if (dentry->d_inode->i_op->put_link)
517− dentry->d_inode->i_op->put_link(dentry, nd);
520+ dentry->d_inode->i_op->put_link(dentry, nd, cookie);
518521 }
519522 dput(dentry);
520523 mntput(path->mnt);
@@ -2344,15 +2347,17 @@ out: · 1823 unmodified lines
23442347 int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
23452348 {
23462349 struct nameidata nd;
2347− int res;
2350+ void *cookie;
2351+
23482352 nd.depth = 0;
2349− res = dentry->d_inode->i_op->follow_link(dentry, &nd);
2350− if (!res) {
2351− res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
2353+ cookie = dentry->d_inode->i_op->follow_link(dentry, &nd);
2354+ if (!IS_ERR(cookie)) {
2355+ int res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
23522356 if (dentry->d_inode->i_op->put_link)
2353− dentry->d_inode->i_op->put_link(dentry, &nd);
2357+ dentry->d_inode->i_op->put_link(dentry, &nd, cookie);
2358+ cookie = ERR_PTR(res);
23542359 }
2355− return res;
2360+ return PTR_ERR(cookie);
23562361 }
23572362
23582363 int vfs_follow_link(struct nameidata *nd, const char *link)
@@ -2395,23 +2400,20 @@ int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) · 36 unmodified lines
23952400 return res;
23962401 }
23972402
2398−int page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
2403+void *page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
23992404 {
2400− struct page *page;
2405+ struct page *page = NULL;
24012406 nd_set_link(nd, page_getlink(dentry, &page));
2402− return 0;
2407+ return page;
24032408 }
24042409
2405−void page_put_link(struct dentry *dentry, struct nameidata *nd)
2410+void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
24062411 {
2407− if (!IS_ERR(nd_get_link(nd))) {
2408− struct page *page;
2409− page = find_get_page(dentry->d_inode->i_mapping, 0);
2410− if (!page)
2411− BUG();
2412+ struct page *page = cookie;
2413+
2414+ if (page) {
24122415 kunmap(page);
24132416 page_cache_release(page);
2414− page_cache_release(page);
24152417 }
24162418 }
24172419
fs/nfs/symlink.c+8−29
@@ -27,26 +27,14 @@ · 26 unmodified lines
2727
2828 /* Symlink caching in the page cache is even more simplistic
2929 * and straight-forward than readdir caching.
30− *
31− * At the beginning of the page we store pointer to struct page in question,
32− * simplifying nfs_put_link() (if inode got invalidated we can't find the page
33− * to be freed via pagecache lookup).
34− * The NUL-terminated string follows immediately thereafter.
3530 */
3631
37−struct nfs_symlink {
38− struct page *page;
39− char body[0];
40−};
41−
4232 static int nfs_symlink_filler(struct inode *inode, struct page *page)
4333 {
44− const unsigned int pgbase = offsetof(struct nfs_symlink, body);
45− const unsigned int pglen = PAGE_SIZE - pgbase;
4634 int error;
4735
4836 lock_kernel();
49− error = NFS_PROTO(inode)->readlink(inode, page, pgbase, pglen);
37+ error = NFS_PROTO(inode)->readlink(inode, page, 0, PAGE_SIZE);
5038 unlock_kernel();
5139 if (error < 0)
5240 goto error;
@@ -60,11 +48,10 @@ error: · 7 unmodified lines
6048 return -EIO;
6149 }
6250
63−static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
51+static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
6452 {
6553 struct inode *inode = dentry->d_inode;
6654 struct page *page;
67− struct nfs_symlink *p;
6855 void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode));
6956 if (err)
7057 goto read_failed;
@@ -78,28 +65,20 @@ static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd) · 7 unmodified lines
7865 err = ERR_PTR(-EIO);
7966 goto getlink_read_error;
8067 }
81− p = kmap(page);
82− p->page = page;
83− nd_set_link(nd, p->body);
84− return 0;
68+ nd_set_link(nd, kmap(page));
69+ return page;
8570
8671 getlink_read_error:
8772 page_cache_release(page);
8873 read_failed:
8974 nd_set_link(nd, err);
90− return 0;
75+ return NULL;
9176 }
9277
93−static void nfs_put_link(struct dentry *dentry, struct nameidata *nd)
78+static void nfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
9479 {
95− char *s = nd_get_link(nd);
96− if (!IS_ERR(s)) {
97− struct nfs_symlink *p;
98− struct page *page;
99−
100− p = container_of(s, struct nfs_symlink, body[0]);
101− page = p->page;
102−
80+ if (cookie) {
81+ struct page *page = cookie;
10382 kunmap(page);
10483 page_cache_release(page);
10584 }
fs/sysfs/symlink.c+3−3
@@ -151,17 +151,17 @@ static int sysfs_getlink(struct dentry *dentry, char * path) · 150 unmodified lines
151151
152152 }
153153
154−static int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
154+static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
155155 {
156156 int error = -ENOMEM;
157157 unsigned long page = get_zeroed_page(GFP_KERNEL);
158158 if (page)
159159 error = sysfs_getlink(dentry, (char *) page);
160160 nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
161− return 0;
161+ return NULL;
162162 }
163163
164−static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd)
164+static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
165165 {
166166 char *page = nd_get_link(nd);
167167 if (!IS_ERR(page))
include/linux/fs.h+4−4
@@ -993,8 +993,8 @@ struct inode_operations { · 992 unmodified lines
993993 int (*rename) (struct inode *, struct dentry *,
994994 struct inode *, struct dentry *);
995995 int (*readlink) (struct dentry *, char __user *,int);
996− int (*follow_link) (struct dentry *, struct nameidata *);
997− void (*put_link) (struct dentry *, struct nameidata *);
996+ void * (*follow_link) (struct dentry *, struct nameidata *);
997+ void (*put_link) (struct dentry *, struct nameidata *, void *);
998998 void (*truncate) (struct inode *);
999999 int (*permission) (struct inode *, int, struct nameidata *);
10001000 int (*setattr) (struct dentry *, struct iattr *);
@@ -1602,8 +1602,8 @@ extern struct file_operations generic_ro_fops; · 601 unmodified lines
16021602 extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
16031603 extern int vfs_follow_link(struct nameidata *, const char *);
16041604 extern int page_readlink(struct dentry *, char __user *, int);
1605−extern int page_follow_link_light(struct dentry *, struct nameidata *);
1606−extern void page_put_link(struct dentry *, struct nameidata *);
1605+extern void *page_follow_link_light(struct dentry *, struct nameidata *);
1606+extern void page_put_link(struct dentry *, struct nameidata *, void *);
16071607 extern int page_symlink(struct inode *inode, const char *symname, int len);
16081608 extern struct inode_operations page_symlink_inode_operations;
16091609 extern int generic_readlink(struct dentry *, char __user *, int);
mm/shmem.c+6−11
@@ -1773,32 +1773,27 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s · 1772 unmodified lines
17731773 return 0;
17741774 }
17751775
1776−static int shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
1776+static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
17771777 {
17781778 nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode));
1779− return 0;
1779+ return NULL;
17801780 }
17811781
1782−static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
1782+static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
17831783 {
17841784 struct page *page = NULL;
17851785 int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
17861786 nd_set_link(nd, res ? ERR_PTR(res) : kmap(page));
1787− return 0;
1787+ return page;
17881788 }
17891789
1790−static void shmem_put_link(struct dentry *dentry, struct nameidata *nd)
1790+static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
17911791 {
17921792 if (!IS_ERR(nd_get_link(nd))) {
1793− struct page *page;
1794−
1795− page = find_get_page(dentry->d_inode->i_mapping, 0);
1796− if (!page)
1797− BUG();
1793+ struct page *page = cookie;
17981794 kunmap(page);
17991795 mark_page_accessed(page);
18001796 page_cache_release(page);
1801− page_cache_release(page);
18021797 }
18031798 }
18041799