Merge to Fedora kernel-2.6.7-1.492
[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 static int nfs_symlink_filler(struct inode *inode, struct page *page)
32 {
33         int error;
34
35         /* We place the length at the beginning of the page,
36          * in host byte order, followed by the string.  The
37          * XDR response verification will NULL terminate it.
38          */
39         lock_kernel();
40         error = NFS_PROTO(inode)->readlink(inode, page);
41         unlock_kernel();
42         if (error < 0)
43                 goto error;
44         SetPageUptodate(page);
45         unlock_page(page);
46         return 0;
47
48 error:
49         SetPageError(page);
50         unlock_page(page);
51         return -EIO;
52 }
53
54 enum {
55         Page_Offset = (PAGE_SIZE - sizeof(void *)) / 4
56 };
57
58 static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
59 {
60         struct inode *inode = dentry->d_inode;
61         struct page *page;
62         u32 *p;
63
64         page = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode));
65         if (page)
66                 goto read_failed;
67         page = read_cache_page(&inode->i_data, 0,
68                                 (filler_t *)nfs_symlink_filler, inode);
69         if (IS_ERR(page))
70                 goto read_failed;
71         if (!PageUptodate(page))
72                 goto getlink_read_error;
73         p = kmap(page);
74         if (*p > Page_Offset * 4 - 1 - 4)
75                 goto too_long;
76         *(struct page **)(p + Page_Offset) = page;
77
78         nd_set_link(nd, (char *)(p+1));
79         return 0;
80
81 too_long:
82         kunmap(page);
83         page_cache_release(page);
84         page = ERR_PTR(-ENAMETOOLONG);
85         goto read_failed;
86 getlink_read_error:
87         page_cache_release(page);
88         page = ERR_PTR(-EIO);
89 read_failed:
90         nd_set_link(nd, (char*)page);
91         return 0;
92 }
93
94 static void nfs_put_link(struct dentry *dentry, struct nameidata *nd)
95 {
96         u32 *s = (u32 *)nd_get_link(nd);
97         if (!IS_ERR(s)) {
98                 struct page *page = *(struct page **)(s + Page_Offset - 1);
99                 kunmap(page);
100                 page_cache_release(page);
101         }
102 }
103
104 /*
105  * symlinks can't do much...
106  */
107 struct inode_operations nfs_symlink_inode_operations = {
108         .readlink       = generic_readlink,
109         .follow_link    = nfs_follow_link,
110         .put_link       = nfs_put_link,
111         .getattr        = nfs_getattr,
112         .setattr        = nfs_setattr,
113 };