#include <linux/compat.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/swap.h>
#include <linux/sched.h>
#include <linux/kmemleak.h>
#include <linux/xattr.h>
#include <linux/hash.h>
#include "delegation.h"
#include "iostat.h"
#include "internal.h"
#include "fscache.h"
#include "nfstrace.h"
static int nfs_opendir(struct inode *, struct file *);
static int nfs_closedir(struct inode *, struct file *);
static int nfs_readdir(struct file *, struct dir_context *);
static int nfs_fsync_dir(struct file *, loff_t, loff_t, int);
static loff_t nfs_llseek_dir(struct file *, loff_t, int);
static void nfs_readdir_clear_array(struct folio *);
static int nfs_do_create(struct inode *dir, struct dentry *dentry,
umode_t mode, int open_flags);
const struct file_operations nfs_dir_operations = …;
const struct address_space_operations nfs_dir_aops = …;
#define NFS_INIT_DTSIZE …
static struct nfs_open_dir_context *
alloc_nfs_open_dir_context(struct inode *dir)
{ … }
static void put_nfs_open_dir_context(struct inode *dir, struct nfs_open_dir_context *ctx)
{ … }
static int
nfs_opendir(struct inode *inode, struct file *filp)
{ … }
static int
nfs_closedir(struct inode *inode, struct file *filp)
{ … }
struct nfs_cache_array_entry { … };
struct nfs_cache_array { … };
struct nfs_readdir_descriptor { … };
static void nfs_set_dtsize(struct nfs_readdir_descriptor *desc, unsigned int sz)
{ … }
static void nfs_shrink_dtsize(struct nfs_readdir_descriptor *desc)
{ … }
static void nfs_grow_dtsize(struct nfs_readdir_descriptor *desc)
{ … }
static void nfs_readdir_folio_init_array(struct folio *folio, u64 last_cookie,
u64 change_attr)
{ … }
static void nfs_readdir_clear_array(struct folio *folio)
{ … }
static void nfs_readdir_folio_reinit_array(struct folio *folio, u64 last_cookie,
u64 change_attr)
{ … }
static struct folio *
nfs_readdir_folio_array_alloc(u64 last_cookie, gfp_t gfp_flags)
{ … }
static void nfs_readdir_folio_array_free(struct folio *folio)
{ … }
static u64 nfs_readdir_array_index_cookie(struct nfs_cache_array *array)
{ … }
static void nfs_readdir_array_set_eof(struct nfs_cache_array *array)
{ … }
static bool nfs_readdir_array_is_full(struct nfs_cache_array *array)
{ … }
static const char *nfs_readdir_copy_name(const char *name, unsigned int len)
{ … }
static size_t nfs_readdir_array_maxentries(void)
{ … }
static int nfs_readdir_array_can_expand(struct nfs_cache_array *array)
{ … }
static int nfs_readdir_folio_array_append(struct folio *folio,
const struct nfs_entry *entry,
u64 *cookie)
{ … }
#define NFS_READDIR_COOKIE_MASK …
static pgoff_t nfs_readdir_folio_cookie_hash(u64 cookie)
{ … }
static bool nfs_readdir_folio_validate(struct folio *folio, u64 last_cookie,
u64 change_attr)
{ … }
static void nfs_readdir_folio_unlock_and_put(struct folio *folio)
{ … }
static void nfs_readdir_folio_init_and_validate(struct folio *folio, u64 cookie,
u64 change_attr)
{ … }
static struct folio *nfs_readdir_folio_get_locked(struct address_space *mapping,
u64 cookie, u64 change_attr)
{ … }
static u64 nfs_readdir_folio_last_cookie(struct folio *folio)
{ … }
static bool nfs_readdir_folio_needs_filling(struct folio *folio)
{ … }
static void nfs_readdir_folio_set_eof(struct folio *folio)
{ … }
static struct folio *nfs_readdir_folio_get_next(struct address_space *mapping,
u64 cookie, u64 change_attr)
{ … }
static inline
int is_32bit_api(void)
{ … }
static
bool nfs_readdir_use_cookie(const struct file *filp)
{ … }
static void nfs_readdir_seek_next_array(struct nfs_cache_array *array,
struct nfs_readdir_descriptor *desc)
{ … }
static void nfs_readdir_rewind_search(struct nfs_readdir_descriptor *desc)
{ … }
static int nfs_readdir_search_for_pos(struct nfs_cache_array *array,
struct nfs_readdir_descriptor *desc)
{ … }
static bool nfs_readdir_array_cookie_in_range(struct nfs_cache_array *array,
u64 cookie)
{ … }
static int nfs_readdir_search_for_cookie(struct nfs_cache_array *array,
struct nfs_readdir_descriptor *desc)
{ … }
static int nfs_readdir_search_array(struct nfs_readdir_descriptor *desc)
{ … }
static int nfs_readdir_xdr_filler(struct nfs_readdir_descriptor *desc,
__be32 *verf, u64 cookie,
struct page **pages, size_t bufsize,
__be32 *verf_res)
{ … }
static int xdr_decode(struct nfs_readdir_descriptor *desc,
struct nfs_entry *entry, struct xdr_stream *xdr)
{ … }
static
int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
{ … }
#define NFS_READDIR_CACHE_USAGE_THRESHOLD …
static bool nfs_use_readdirplus(struct inode *dir, struct dir_context *ctx,
unsigned int cache_hits,
unsigned int cache_misses)
{ … }
void nfs_readdir_record_entry_cache_hit(struct inode *dir)
{ … }
void nfs_readdir_record_entry_cache_miss(struct inode *dir)
{ … }
static void nfs_lookup_advise_force_readdirplus(struct inode *dir,
unsigned int flags)
{ … }
static
void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry,
unsigned long dir_verifier)
{ … }
static int nfs_readdir_entry_decode(struct nfs_readdir_descriptor *desc,
struct nfs_entry *entry,
struct xdr_stream *stream)
{ … }
static int nfs_readdir_folio_filler(struct nfs_readdir_descriptor *desc,
struct nfs_entry *entry,
struct page **xdr_pages, unsigned int buflen,
struct folio **arrays, size_t narrays,
u64 change_attr)
{ … }
static void nfs_readdir_free_pages(struct page **pages, size_t npages)
{ … }
static struct page **nfs_readdir_alloc_pages(size_t npages)
{ … }
static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
__be32 *verf_arg, __be32 *verf_res,
struct folio **arrays, size_t narrays)
{ … }
static void nfs_readdir_folio_put(struct nfs_readdir_descriptor *desc)
{ … }
static void
nfs_readdir_folio_unlock_and_put_cached(struct nfs_readdir_descriptor *desc)
{ … }
static struct folio *
nfs_readdir_folio_get_cached(struct nfs_readdir_descriptor *desc)
{ … }
static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
{ … }
static int readdir_search_pagecache(struct nfs_readdir_descriptor *desc)
{ … }
#define NFS_READDIR_CACHE_MISS_THRESHOLD …
static void nfs_do_filldir(struct nfs_readdir_descriptor *desc,
const __be32 *verf)
{ … }
static int uncached_readdir(struct nfs_readdir_descriptor *desc)
{ … }
static bool nfs_readdir_handle_cache_misses(struct inode *inode,
struct nfs_readdir_descriptor *desc,
unsigned int cache_misses,
bool force_clear)
{ … }
static int nfs_readdir(struct file *file, struct dir_context *ctx)
{ … }
static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
{ … }
static int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end,
int datasync)
{ … }
void nfs_force_lookup_revalidate(struct inode *dir)
{ … }
EXPORT_SYMBOL_GPL(…);
static bool nfs_verify_change_attribute(struct inode *dir, unsigned long verf)
{ … }
static void nfs_set_verifier_delegated(unsigned long *verf)
{ … }
#if IS_ENABLED(CONFIG_NFS_V4)
static void nfs_unset_verifier_delegated(unsigned long *verf)
{ … }
#endif
static bool nfs_test_verifier_delegated(unsigned long verf)
{ … }
static bool nfs_verifier_is_delegated(struct dentry *dentry)
{ … }
static void nfs_set_verifier_locked(struct dentry *dentry, unsigned long verf)
{ … }
void nfs_set_verifier(struct dentry *dentry, unsigned long verf)
{ … }
EXPORT_SYMBOL_GPL(…);
#if IS_ENABLED(CONFIG_NFS_V4)
void nfs_clear_verifier_delegated(struct inode *inode)
{ … }
EXPORT_SYMBOL_GPL(…);
#endif
static int nfs_dentry_verify_change(struct inode *dir, struct dentry *dentry)
{ … }
static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
int rcu_walk)
{ … }
static int nfs_is_exclusive_create(struct inode *dir, unsigned int flags)
{ … }
static
int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
{ … }
static void nfs_mark_dir_for_revalidate(struct inode *inode)
{ … }
static inline
int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
unsigned int flags)
{ … }
static int
nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
struct inode *inode, int error)
{ … }
static int
nfs_lookup_revalidate_negative(struct inode *dir, struct dentry *dentry,
unsigned int flags)
{ … }
static int
nfs_lookup_revalidate_delegated(struct inode *dir, struct dentry *dentry,
struct inode *inode)
{ … }
static int nfs_lookup_revalidate_dentry(struct inode *dir,
struct dentry *dentry,
struct inode *inode, unsigned int flags)
{ … }
static int
nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
unsigned int flags)
{ … }
static int
__nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags,
int (*reval)(struct inode *, struct dentry *, unsigned int))
{ … }
static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
{ … }
static void block_revalidate(struct dentry *dentry)
{ … }
static void unblock_revalidate(struct dentry *dentry)
{ … }
static int nfs_weak_revalidate(struct dentry *dentry, unsigned int flags)
{ … }
static int nfs_dentry_delete(const struct dentry *dentry)
{ … }
static void nfs_drop_nlink(struct inode *inode)
{ … }
static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
{ … }
static void nfs_d_release(struct dentry *dentry)
{ … }
const struct dentry_operations nfs_dentry_operations = …;
EXPORT_SYMBOL_GPL(…);
struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
{ … }
EXPORT_SYMBOL_GPL(…);
void nfs_d_prune_case_insensitive_aliases(struct inode *inode)
{ … }
EXPORT_SYMBOL_GPL(…);
#if IS_ENABLED(CONFIG_NFS_V4)
static int nfs4_lookup_revalidate(struct dentry *, unsigned int);
const struct dentry_operations nfs4_dentry_operations = …;
EXPORT_SYMBOL_GPL(…);
static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, int open_flags, struct file *filp)
{ … }
static int do_open(struct inode *inode, struct file *filp)
{ … }
static int nfs_finish_open(struct nfs_open_context *ctx,
struct dentry *dentry,
struct file *file, unsigned open_flags)
{ … }
int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
struct file *file, unsigned open_flags,
umode_t mode)
{ … }
EXPORT_SYMBOL_GPL(…);
static int
nfs4_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
unsigned int flags)
{ … }
static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
{ … }
#endif
int nfs_atomic_open_v23(struct inode *dir, struct dentry *dentry,
struct file *file, unsigned int open_flags,
umode_t mode)
{ … }
EXPORT_SYMBOL_GPL(…);
struct dentry *
nfs_add_or_obtain(struct dentry *dentry, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{ … }
EXPORT_SYMBOL_GPL(…);
int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{ … }
EXPORT_SYMBOL_GPL(…);
static int nfs_do_create(struct inode *dir, struct dentry *dentry,
umode_t mode, int open_flags)
{ … }
int nfs_create(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, bool excl)
{ … }
EXPORT_SYMBOL_GPL(…);
int
nfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t rdev)
{ … }
EXPORT_SYMBOL_GPL(…);
int nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode)
{ … }
EXPORT_SYMBOL_GPL(…);
static void nfs_dentry_handle_enoent(struct dentry *dentry)
{ … }
static void nfs_dentry_remove_handle_error(struct inode *dir,
struct dentry *dentry, int error)
{ … }
int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{ … }
EXPORT_SYMBOL_GPL(…);
static int nfs_safe_remove(struct dentry *dentry)
{ … }
int nfs_unlink(struct inode *dir, struct dentry *dentry)
{ … }
EXPORT_SYMBOL_GPL(…);
int nfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, const char *symname)
{ … }
EXPORT_SYMBOL_GPL(…);
int
nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{ … }
EXPORT_SYMBOL_GPL(…);
static void
nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
{ … }
int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
struct dentry *old_dentry, struct inode *new_dir,
struct dentry *new_dentry, unsigned int flags)
{ … }
EXPORT_SYMBOL_GPL(…);
static DEFINE_SPINLOCK(nfs_access_lru_lock);
static LIST_HEAD(nfs_access_lru_list);
static atomic_long_t nfs_access_nr_entries;
static unsigned long nfs_access_max_cachesize = …;
module_param(nfs_access_max_cachesize, ulong, 0644);
MODULE_PARM_DESC(…) …;
static void nfs_access_free_entry(struct nfs_access_entry *entry)
{ … }
static void nfs_access_free_list(struct list_head *head)
{ … }
static unsigned long
nfs_do_access_cache_scan(unsigned int nr_to_scan)
{ … }
unsigned long
nfs_access_cache_scan(struct shrinker *shrink, struct shrink_control *sc)
{ … }
unsigned long
nfs_access_cache_count(struct shrinker *shrink, struct shrink_control *sc)
{ … }
static void
nfs_access_cache_enforce_limit(void)
{ … }
static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head)
{ … }
void nfs_access_zap_cache(struct inode *inode)
{ … }
EXPORT_SYMBOL_GPL(…);
static int access_cmp(const struct cred *a, const struct nfs_access_entry *b)
{ … }
static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, const struct cred *cred)
{ … }
static u64 nfs_access_login_time(const struct task_struct *task,
const struct cred *cred)
{ … }
static int nfs_access_get_cached_locked(struct inode *inode, const struct cred *cred, u32 *mask, bool may_block)
{ … }
static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cred, u32 *mask)
{ … }
int nfs_access_get_cached(struct inode *inode, const struct cred *cred,
u32 *mask, bool may_block)
{ … }
EXPORT_SYMBOL_GPL(…);
static void nfs_access_add_rbtree(struct inode *inode,
struct nfs_access_entry *set,
const struct cred *cred)
{ … }
void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set,
const struct cred *cred)
{ … }
EXPORT_SYMBOL_GPL(…);
#define NFS_MAY_READ …
#define NFS_MAY_WRITE …
#define NFS_FILE_MAY_WRITE …
#define NFS_DIR_MAY_WRITE …
#define NFS_MAY_LOOKUP …
#define NFS_MAY_EXECUTE …
static int
nfs_access_calc_mask(u32 access_result, umode_t umode)
{ … }
void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result)
{ … }
EXPORT_SYMBOL_GPL(…);
static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
{ … }
static int nfs_open_permission_mask(int openflags)
{ … }
int nfs_may_open(struct inode *inode, const struct cred *cred, int openflags)
{ … }
EXPORT_SYMBOL_GPL(…);
static int nfs_execute_ok(struct inode *inode, int mask)
{ … }
int nfs_permission(struct mnt_idmap *idmap,
struct inode *inode,
int mask)
{ … }
EXPORT_SYMBOL_GPL(…);