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 32 static int nfs_symlink_filler(struct inode *inode, struct page *page) 33 { 34 int error; 35 36 lock_kernel(); 37 error = NFS_PROTO(inode)->readlink(inode, page, 0, PAGE_SIZE); 38 unlock_kernel(); 39 if (error < 0) 40 goto error; 41 SetPageUptodate(page); 42 unlock_page(page); 43 return 0; 44 45 error: 46 SetPageError(page); 47 unlock_page(page); 48 return -EIO; 49 } 50 51 static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd) 52 { 53 struct inode *inode = dentry->d_inode; 54 struct page *page; 55 void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode)); 56 if (err) 57 goto read_failed; 58 page = read_cache_page(&inode->i_data, 0, 59 (filler_t *)nfs_symlink_filler, inode); 60 if (IS_ERR(page)) { 61 err = page; 62 goto read_failed; 63 } 64 if (!PageUptodate(page)) { 65 err = ERR_PTR(-EIO); 66 goto getlink_read_error; 67 } 68 nd_set_link(nd, kmap(page)); 69 return page; 70 71 getlink_read_error: 72 page_cache_release(page); 73 read_failed: 74 nd_set_link(nd, err); 75 return NULL; 76 } 77 78 static void nfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) 79 { 80 if (cookie) { 81 struct page *page = cookie; 82 kunmap(page); 83 page_cache_release(page); 84 } 85 } 86 87 /* 88 * symlinks can't do much... 89 */ 90 struct inode_operations nfs_symlink_inode_operations = { 91 .readlink = generic_readlink, 92 .follow_link = nfs_follow_link, 93 .put_link = nfs_put_link, 94 .getattr = nfs_getattr, 95 .setattr = nfs_setattr, 96 }; 97