Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  linux/fs/nfs/symlink.c
0004  *
0005  *  Copyright (C) 1992  Rick Sladkey
0006  *
0007  *  Optimization changes Copyright (C) 1994 Florian La Roche
0008  *
0009  *  Jun 7 1999, cache symlink lookups in the page cache.  -DaveM
0010  *
0011  *  nfs symlink handling code
0012  */
0013 
0014 #include <linux/time.h>
0015 #include <linux/errno.h>
0016 #include <linux/sunrpc/clnt.h>
0017 #include <linux/nfs.h>
0018 #include <linux/nfs2.h>
0019 #include <linux/nfs_fs.h>
0020 #include <linux/pagemap.h>
0021 #include <linux/stat.h>
0022 #include <linux/mm.h>
0023 #include <linux/string.h>
0024 
0025 /* Symlink caching in the page cache is even more simplistic
0026  * and straight-forward than readdir caching.
0027  */
0028 
0029 static int nfs_symlink_filler(struct file *file, struct folio *folio)
0030 {
0031     struct inode *inode = folio->mapping->host;
0032     int error;
0033 
0034     error = NFS_PROTO(inode)->readlink(inode, &folio->page, 0, PAGE_SIZE);
0035     if (error < 0)
0036         goto error;
0037     folio_mark_uptodate(folio);
0038     folio_unlock(folio);
0039     return 0;
0040 
0041 error:
0042     folio_set_error(folio);
0043     folio_unlock(folio);
0044     return -EIO;
0045 }
0046 
0047 static const char *nfs_get_link(struct dentry *dentry,
0048                 struct inode *inode,
0049                 struct delayed_call *done)
0050 {
0051     struct page *page;
0052     void *err;
0053 
0054     if (!dentry) {
0055         err = ERR_PTR(nfs_revalidate_mapping_rcu(inode));
0056         if (err)
0057             return err;
0058         page = find_get_page(inode->i_mapping, 0);
0059         if (!page)
0060             return ERR_PTR(-ECHILD);
0061         if (!PageUptodate(page)) {
0062             put_page(page);
0063             return ERR_PTR(-ECHILD);
0064         }
0065     } else {
0066         err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
0067         if (err)
0068             return err;
0069         page = read_cache_page(&inode->i_data, 0, nfs_symlink_filler,
0070                 NULL);
0071         if (IS_ERR(page))
0072             return ERR_CAST(page);
0073     }
0074     set_delayed_call(done, page_put_link, page);
0075     return page_address(page);
0076 }
0077 
0078 /*
0079  * symlinks can't do much...
0080  */
0081 const struct inode_operations nfs_symlink_inode_operations = {
0082     .get_link   = nfs_get_link,
0083     .getattr    = nfs_getattr,
0084     .setattr    = nfs_setattr,
0085 };