xref: /openbmc/linux/fs/nfs/symlink.c (revision 1da177e4)
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 };
118