vserver 1.9.3
[linux-2.6.git] / fs / nfs / symlink.c
1 /*
2  *  linux/fs/nfs/symlink.c
3  *
4  *  Copyright (C) 1992  Rick Sladkey
5  *
6  *  Optimization changes Copyright (C) 1994 Florian La Roche
7  *
8  *  Jun 7 1999, cache symlink lookups in the page cache.  -DaveM
9  *
10  *  nfs symlink handling code
11  */
12
13 #define NFS_NEED_XDR_TYPES
14 #include <linux/time.h>
15 #include <linux/errno.h>
16 #include <linux/sunrpc/clnt.h>
17 #include <linux/nfs.h>
18 #include <linux/nfs2.h>
19 #include <linux/nfs_fs.h>
20 #include <linux/pagemap.h>
21 #include <linux/stat.h>
22 #include <linux/mm.h>
23 #include <linux/slab.h>
24 #include <linux/string.h>
25 #include <linux/smp_lock.h>
26 #include <linux/namei.h>
27
28 /* Symlink caching in the page cache is even more simplistic
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  */
36
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)
43 {
44         const unsigned int pgbase = offsetof(struct nfs_symlink, body);
45         const unsigned int pglen = PAGE_SIZE - pgbase;
46         int error;
47
48         lock_kernel();
49         error = NFS_PROTO(inode)->readlink(inode, page, pgbase, pglen);
50         unlock_kernel();
51         if (error < 0)
52                 goto error;
53         SetPageUptodate(page);
54         unlock_page(page);
55         return 0;
56
57 error:
58         SetPageError(page);
59         unlock_page(page);
60         return -EIO;
61 }
62
63 static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
64 {
65         struct inode *inode = dentry->d_inode;
66         struct page *page;
67         struct nfs_symlink *p;
68         void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode));
69         if (err)
70                 goto read_failed;
71         page = read_cache_page(&inode->i_data, 0,
72                                 (filler_t *)nfs_symlink_filler, inode);
73         if (IS_ERR(page)) {
74                 err = page;
75                 goto read_failed;
76         }
77         if (!PageUptodate(page)) {
78                 err = ERR_PTR(-EIO);
79                 goto getlink_read_error;
80         }
81         p = kmap(page);
82         p->page = page;
83         nd_set_link(nd, p->body);
84         return 0;
85
86 getlink_read_error:
87         page_cache_release(page);
88 read_failed:
89         nd_set_link(nd, err);
90         return 0;
91 }
92
93 static void nfs_put_link(struct dentry *dentry, struct nameidata *nd)
94 {
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
103                 kunmap(page);
104                 page_cache_release(page);
105         }
106 }
107
108 /*
109  * symlinks can't do much...
110  */
111 struct inode_operations nfs_symlink_inode_operations = {
112         .readlink       = generic_readlink,
113         .follow_link    = nfs_follow_link,
114         .put_link       = nfs_put_link,
115         .getattr        = nfs_getattr,
116         .setattr        = nfs_setattr,
117 };