diff options
Diffstat (limited to 'fs/nfs/symlink.c')
-rw-r--r-- | fs/nfs/symlink.c | 37 |
1 files changed, 8 insertions, 29 deletions
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 35f106599144..18dc95b0b646 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c | |||
@@ -27,26 +27,14 @@ | |||
27 | 27 | ||
28 | /* Symlink caching in the page cache is even more simplistic | 28 | /* Symlink caching in the page cache is even more simplistic |
29 | * and straight-forward than readdir caching. | 29 | * 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. | ||
35 | */ | 30 | */ |
36 | 31 | ||
37 | struct nfs_symlink { | ||
38 | struct page *page; | ||
39 | char body[0]; | ||
40 | }; | ||
41 | |||
42 | static int nfs_symlink_filler(struct inode *inode, struct page *page) | 32 | static int nfs_symlink_filler(struct inode *inode, struct page *page) |
43 | { | 33 | { |
44 | const unsigned int pgbase = offsetof(struct nfs_symlink, body); | ||
45 | const unsigned int pglen = PAGE_SIZE - pgbase; | ||
46 | int error; | 34 | int error; |
47 | 35 | ||
48 | lock_kernel(); | 36 | lock_kernel(); |
49 | error = NFS_PROTO(inode)->readlink(inode, page, pgbase, pglen); | 37 | error = NFS_PROTO(inode)->readlink(inode, page, 0, PAGE_SIZE); |
50 | unlock_kernel(); | 38 | unlock_kernel(); |
51 | if (error < 0) | 39 | if (error < 0) |
52 | goto error; | 40 | goto error; |
@@ -60,11 +48,10 @@ error: | |||
60 | return -EIO; | 48 | return -EIO; |
61 | } | 49 | } |
62 | 50 | ||
63 | static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd) | 51 | static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd) |
64 | { | 52 | { |
65 | struct inode *inode = dentry->d_inode; | 53 | struct inode *inode = dentry->d_inode; |
66 | struct page *page; | 54 | struct page *page; |
67 | struct nfs_symlink *p; | ||
68 | void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode)); | 55 | void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode)); |
69 | if (err) | 56 | if (err) |
70 | goto read_failed; | 57 | goto read_failed; |
@@ -78,28 +65,20 @@ static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
78 | err = ERR_PTR(-EIO); | 65 | err = ERR_PTR(-EIO); |
79 | goto getlink_read_error; | 66 | goto getlink_read_error; |
80 | } | 67 | } |
81 | p = kmap(page); | 68 | nd_set_link(nd, kmap(page)); |
82 | p->page = page; | 69 | return page; |
83 | nd_set_link(nd, p->body); | ||
84 | return 0; | ||
85 | 70 | ||
86 | getlink_read_error: | 71 | getlink_read_error: |
87 | page_cache_release(page); | 72 | page_cache_release(page); |
88 | read_failed: | 73 | read_failed: |
89 | nd_set_link(nd, err); | 74 | nd_set_link(nd, err); |
90 | return 0; | 75 | return NULL; |
91 | } | 76 | } |
92 | 77 | ||
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) |
94 | { | 79 | { |
95 | char *s = nd_get_link(nd); | 80 | if (cookie) { |
96 | if (!IS_ERR(s)) { | 81 | struct page *page = cookie; |
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 | |||
103 | kunmap(page); | 82 | kunmap(page); |
104 | page_cache_release(page); | 83 | page_cache_release(page); |
105 | } | 84 | } |