linux/fs/nfs/inode.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 *  linux/fs/nfs/inode.c
 *
 *  Copyright (C) 1992  Rick Sladkey
 *
 *  nfs inode and superblock handling functions
 *
 *  Modularised by Alan Cox <[email protected]>, while hacking some
 *  experimental NFS changes. Modularisation taken straight from SYS5 fs.
 *
 *  Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
 *  [email protected]
 *
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/metrics.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
#include <linux/lockd/bind.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/vfs.h>
#include <linux/inet.h>
#include <linux/nfs_xdr.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/iversion.h>

#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
#include "iostat.h"
#include "internal.h"
#include "fscache.h"
#include "pnfs.h"
#include "nfs.h"
#include "netns.h"
#include "sysfs.h"

#include "nfstrace.h"

#define NFSDBG_FACILITY

#define NFS_64_BIT_INODE_NUMBERS_ENABLED

/* Default is to see 64-bit inode numbers */
static bool enable_ino64 =;

static int nfs_update_inode(struct inode *, struct nfs_fattr *);

static struct kmem_cache * nfs_inode_cachep;

static inline unsigned long
nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
{}

int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
{}
EXPORT_SYMBOL_GPL();

/**
 * nfs_compat_user_ino64 - returns the user-visible inode number
 * @fileid: 64-bit fileid
 *
 * This function returns a 32-bit inode number if the boot parameter
 * nfs.enable_ino64 is zero.
 */
u64 nfs_compat_user_ino64(u64 fileid)
{}

int nfs_drop_inode(struct inode *inode)
{}
EXPORT_SYMBOL_GPL();

void nfs_clear_inode(struct inode *inode)
{}
EXPORT_SYMBOL_GPL();

void nfs_evict_inode(struct inode *inode)
{}

int nfs_sync_inode(struct inode *inode)
{}
EXPORT_SYMBOL_GPL();

/**
 * nfs_sync_mapping - helper to flush all mmapped dirty data to disk
 * @mapping: pointer to struct address_space
 */
int nfs_sync_mapping(struct address_space *mapping)
{}

static int nfs_attribute_timeout(struct inode *inode)
{}

static bool nfs_check_cache_flags_invalid(struct inode *inode,
					  unsigned long flags)
{}

bool nfs_check_cache_invalid(struct inode *inode, unsigned long flags)
{}
EXPORT_SYMBOL_GPL();

#ifdef CONFIG_NFS_V4_2
static bool nfs_has_xattr_cache(const struct nfs_inode *nfsi)
{}
#else
static bool nfs_has_xattr_cache(const struct nfs_inode *nfsi)
{
	return false;
}
#endif

void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
{}
EXPORT_SYMBOL_GPL();

/*
 * Invalidate the local caches
 */
static void nfs_zap_caches_locked(struct inode *inode)
{}

void nfs_zap_caches(struct inode *inode)
{}

void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
{}

void nfs_zap_acl_cache(struct inode *inode)
{}
EXPORT_SYMBOL_GPL();

void nfs_invalidate_atime(struct inode *inode)
{}
EXPORT_SYMBOL_GPL();

/*
 * Invalidate, but do not unhash, the inode.
 * NB: must be called with inode->i_lock held!
 */
static void nfs_set_inode_stale_locked(struct inode *inode)
{}

void nfs_set_inode_stale(struct inode *inode)
{}

struct nfs_find_desc {};

/*
 * In NFSv3 we can have 64bit inode numbers. In order to support
 * this, and re-exported directories (also seen in NFSv2)
 * we are forced to allow 2 different inodes to have the same
 * i_ino.
 */
static int
nfs_find_actor(struct inode *inode, void *opaque)
{}

static int
nfs_init_locked(struct inode *inode, void *opaque)
{}

#ifdef CONFIG_NFS_V4_SECURITY_LABEL
static void nfs_clear_label_invalid(struct inode *inode)
{}

void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
{}

struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
{}
EXPORT_SYMBOL_GPL();
#else
void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
{
}
#endif
EXPORT_SYMBOL_GPL();

/* Search for inode identified by fh, fileid and i_mode in inode cache. */
struct inode *
nfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh)
{}

static void nfs_inode_init_regular(struct nfs_inode *nfsi)
{}

static void nfs_inode_init_dir(struct nfs_inode *nfsi)
{}

/*
 * This is our front-end to iget that looks up inodes by file handle
 * instead of inode number.
 */
struct inode *
nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
{}
EXPORT_SYMBOL_GPL();

static void
nfs_fattr_fixup_delegated(struct inode *inode, struct nfs_fattr *fattr)
{}

void nfs_update_delegated_atime(struct inode *inode)
{}

void nfs_update_delegated_mtime_locked(struct inode *inode)
{}

void nfs_update_delegated_mtime(struct inode *inode)
{}
EXPORT_SYMBOL_GPL();

#define NFS_VALID_ATTRS

int
nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
	    struct iattr *attr)
{}
EXPORT_SYMBOL_GPL();

/**
 * nfs_vmtruncate - unmap mappings "freed" by truncate() syscall
 * @inode: inode of the file used
 * @offset: file offset to start truncating
 *
 * This is a copy of the common vmtruncate, but with the locking
 * corrected to take into account the fact that NFS requires
 * inode->i_size to be updated under the inode->i_lock.
 * Note: must be called with inode->i_lock held!
 */
static int nfs_vmtruncate(struct inode * inode, loff_t offset)
{}

/**
 * nfs_setattr_update_inode - Update inode metadata after a setattr call.
 * @inode: pointer to struct inode
 * @attr: pointer to struct iattr
 * @fattr: pointer to struct nfs_fattr
 *
 * Note: we do this in the *proc.c in order to ensure that
 *       it works for things like exclusive creates too.
 */
void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
		struct nfs_fattr *fattr)
{}
EXPORT_SYMBOL_GPL();

/*
 * Don't request help from readdirplus if the file is being written to,
 * or if attribute caching is turned off
 */
static bool nfs_getattr_readdirplus_enable(const struct inode *inode)
{}

static void nfs_readdirplus_parent_cache_miss(struct dentry *dentry)
{}

static void nfs_readdirplus_parent_cache_hit(struct dentry *dentry)
{}

static u32 nfs_get_valid_attrmask(struct inode *inode)
{}

int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
		struct kstat *stat, u32 request_mask, unsigned int query_flags)
{}
EXPORT_SYMBOL_GPL();

static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
{}

static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx)
{}

struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
{}
EXPORT_SYMBOL_GPL();

void nfs_put_lock_context(struct nfs_lock_context *l_ctx)
{}
EXPORT_SYMBOL_GPL();

/**
 * nfs_close_context - Common close_context() routine NFSv2/v3
 * @ctx: pointer to context
 * @is_sync: is this a synchronous close
 *
 * Ensure that the attributes are up to date if we're mounted
 * with close-to-open semantics and we have cached data that will
 * need to be revalidated on open.
 */
void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
{}
EXPORT_SYMBOL_GPL();

struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
						fmode_t f_mode,
						struct file *filp)
{}
EXPORT_SYMBOL_GPL();

struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
{}
EXPORT_SYMBOL_GPL();

static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
{}

void put_nfs_open_context(struct nfs_open_context *ctx)
{}
EXPORT_SYMBOL_GPL();

static void put_nfs_open_context_sync(struct nfs_open_context *ctx)
{}

/*
 * Ensure that mmap has a recent RPC credential for use when writing out
 * shared pages
 */
void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
{}
EXPORT_SYMBOL_GPL();

void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
{}
EXPORT_SYMBOL_GPL();

/*
 * Given an inode, search for an open context with the desired characteristics
 */
struct nfs_open_context *nfs_find_open_context(struct inode *inode, const struct cred *cred, fmode_t mode)
{}

void nfs_file_clear_open_context(struct file *filp)
{}

/*
 * These allocate and release file read/write context information.
 */
int nfs_open(struct inode *inode, struct file *filp)
{}

/*
 * This function is called whenever some part of NFS notices that
 * the cached attributes have to be refreshed.
 */
int
__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{}

int nfs_attribute_cache_expired(struct inode *inode)
{}

/**
 * nfs_revalidate_inode - Revalidate the inode attributes
 * @inode: pointer to inode struct
 * @flags: cache flags to check
 *
 * Updates inode attribute information by retrieving the data from the server.
 */
int nfs_revalidate_inode(struct inode *inode, unsigned long flags)
{}
EXPORT_SYMBOL_GPL();

static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
{}

/**
 * nfs_clear_invalid_mapping - Conditionally clear a mapping
 * @mapping: pointer to mapping
 *
 * If the NFS_INO_INVALID_DATA inode flag is set, clear the mapping.
 */
int nfs_clear_invalid_mapping(struct address_space *mapping)
{}

bool nfs_mapping_need_revalidate_inode(struct inode *inode)
{}

int nfs_revalidate_mapping_rcu(struct inode *inode)
{}

/**
 * nfs_revalidate_mapping - Revalidate the pagecache
 * @inode: pointer to host inode
 * @mapping: pointer to mapping
 */
int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
{}

static bool nfs_file_has_writers(struct nfs_inode *nfsi)
{}

static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi)
{}

static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{}

/**
 * nfs_check_inode_attributes - verify consistency of the inode attribute cache
 * @inode: pointer to inode
 * @fattr: updated attributes
 *
 * Verifies the attribute cache. If we have just changed the attributes,
 * so that fattr carries weak cache consistency data, then it may
 * also update the ctime/mtime/change_attribute.
 */
static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fattr)
{}

static atomic_long_t nfs_attr_generation_counter;

static unsigned long nfs_read_attr_generation_counter(void)
{}

unsigned long nfs_inc_attr_generation_counter(void)
{}
EXPORT_SYMBOL_GPL();

void nfs_fattr_init(struct nfs_fattr *fattr)
{}
EXPORT_SYMBOL_GPL();

/**
 * nfs_fattr_set_barrier
 * @fattr: attributes
 *
 * Used to set a barrier after an attribute was updated. This
 * barrier ensures that older attributes from RPC calls that may
 * have raced with our update cannot clobber these new values.
 * Note that you are still responsible for ensuring that other
 * operations which change the attribute on the server do not
 * collide.
 */
void nfs_fattr_set_barrier(struct nfs_fattr *fattr)
{}

struct nfs_fattr *nfs_alloc_fattr(void)
{}
EXPORT_SYMBOL_GPL();

struct nfs_fattr *nfs_alloc_fattr_with_label(struct nfs_server *server)
{}
EXPORT_SYMBOL_GPL();

struct nfs_fh *nfs_alloc_fhandle(void)
{}
EXPORT_SYMBOL_GPL();

#ifdef NFS_DEBUG
/*
 * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle
 *                             in the same way that wireshark does
 *
 * @fh: file handle
 *
 * For debugging only.
 */
u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh)
{}
EXPORT_SYMBOL_GPL();

/*
 * _nfs_display_fhandle - display an NFS file handle on the console
 *
 * @fh: file handle to display
 * @caption: display caption
 *
 * For debugging only.
 */
void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption)
{}
EXPORT_SYMBOL_GPL();
#endif

/**
 * nfs_inode_attrs_cmp_generic - compare attributes
 * @fattr: attributes
 * @inode: pointer to inode
 *
 * Attempt to divine whether or not an RPC call reply carrying stale
 * attributes got scheduled after another call carrying updated ones.
 * Note also the check for wraparound of 'attr_gencount'
 *
 * The function returns '1' if it thinks the attributes in @fattr are
 * more recent than the ones cached in @inode. Otherwise it returns
 * the value '0'.
 */
static int nfs_inode_attrs_cmp_generic(const struct nfs_fattr *fattr,
				       const struct inode *inode)
{}

/**
 * nfs_inode_attrs_cmp_monotonic - compare attributes
 * @fattr: attributes
 * @inode: pointer to inode
 *
 * Attempt to divine whether or not an RPC call reply carrying stale
 * attributes got scheduled after another call carrying updated ones.
 *
 * We assume that the server observes monotonic semantics for
 * the change attribute, so a larger value means that the attributes in
 * @fattr are more recent, in which case the function returns the
 * value '1'.
 * A return value of '0' indicates no measurable change
 * A return value of '-1' means that the attributes in @inode are
 * more recent.
 */
static int nfs_inode_attrs_cmp_monotonic(const struct nfs_fattr *fattr,
					 const struct inode *inode)
{}

/**
 * nfs_inode_attrs_cmp_strict_monotonic - compare attributes
 * @fattr: attributes
 * @inode: pointer to inode
 *
 * Attempt to divine whether or not an RPC call reply carrying stale
 * attributes got scheduled after another call carrying updated ones.
 *
 * We assume that the server observes strictly monotonic semantics for
 * the change attribute, so a larger value means that the attributes in
 * @fattr are more recent, in which case the function returns the
 * value '1'.
 * A return value of '-1' means that the attributes in @inode are
 * more recent or unchanged.
 */
static int nfs_inode_attrs_cmp_strict_monotonic(const struct nfs_fattr *fattr,
						const struct inode *inode)
{}

/**
 * nfs_inode_attrs_cmp - compare attributes
 * @fattr: attributes
 * @inode: pointer to inode
 *
 * This function returns '1' if it thinks the attributes in @fattr are
 * more recent than the ones cached in @inode. It returns '-1' if
 * the attributes in @inode are more recent than the ones in @fattr,
 * and it returns 0 if not sure.
 */
static int nfs_inode_attrs_cmp(const struct nfs_fattr *fattr,
			       const struct inode *inode)
{}

/**
 * nfs_inode_finish_partial_attr_update - complete a previous inode update
 * @fattr: attributes
 * @inode: pointer to inode
 *
 * Returns '1' if the last attribute update left the inode cached
 * attributes in a partially unrevalidated state, and @fattr
 * matches the change attribute of that partial update.
 * Otherwise returns '0'.
 */
static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
						const struct inode *inode)
{}

static void nfs_ooo_merge(struct nfs_inode *nfsi,
			  u64 start, u64 end)
{}

static void nfs_ooo_record(struct nfs_inode *nfsi,
			   struct nfs_fattr *fattr)
{}

static int nfs_refresh_inode_locked(struct inode *inode,
				    struct nfs_fattr *fattr)
{}

/**
 * nfs_refresh_inode - try to update the inode attribute cache
 * @inode: pointer to inode
 * @fattr: updated attributes
 *
 * Check that an RPC call that returned attributes has not overlapped with
 * other recent updates of the inode metadata, then decide whether it is
 * safe to do a full update of the inode attributes, or whether just to
 * call nfs_check_inode_attributes.
 */
int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{}
EXPORT_SYMBOL_GPL();

static int nfs_post_op_update_inode_locked(struct inode *inode,
		struct nfs_fattr *fattr, unsigned int invalid)
{}

/**
 * nfs_post_op_update_inode - try to update the inode attribute cache
 * @inode: pointer to inode
 * @fattr: updated attributes
 *
 * After an operation that has changed the inode metadata, mark the
 * attribute cache as being invalid, then try to update it.
 *
 * NB: if the server didn't return any post op attributes, this
 * function will force the retrieval of attributes before the next
 * NFS request.  Thus it should be used only for operations that
 * are expected to change one or more attributes, to avoid
 * unnecessary NFS requests and trips through nfs_update_inode().
 */
int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{}
EXPORT_SYMBOL_GPL();

/**
 * nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache
 * @inode: pointer to inode
 * @fattr: updated attributes
 *
 * After an operation that has changed the inode metadata, mark the
 * attribute cache as being invalid, then try to update it. Fake up
 * weak cache consistency data, if none exist.
 *
 * This function is mainly designed to be used by the ->write_done() functions.
 */
int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr)
{}

/**
 * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
 * @inode: pointer to inode
 * @fattr: updated attributes
 *
 * After an operation that has changed the inode metadata, mark the
 * attribute cache as being invalid, then try to update it. Fake up
 * weak cache consistency data, if none exist.
 *
 * This function is mainly designed to be used by the ->write_done() functions.
 */
int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
{}
EXPORT_SYMBOL_GPL();


/*
 * Many nfs protocol calls return the new file attributes after
 * an operation.  Here we update the inode to reflect the state
 * of the server's inode.
 *
 * This is a bit tricky because we have to make sure all dirty pages
 * have been sent off to the server before calling invalidate_inode_pages.
 * To make sure no other process adds more write requests while we try
 * our best to flush them, we make them sleep during the attribute refresh.
 *
 * A very similar scenario holds for the dir cache.
 */
static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{}

struct inode *nfs_alloc_inode(struct super_block *sb)
{}
EXPORT_SYMBOL_GPL();

void nfs_free_inode(struct inode *inode)
{}
EXPORT_SYMBOL_GPL();

static inline void nfs4_init_once(struct nfs_inode *nfsi)
{}

static void init_once(void *foo)
{}

static int __init nfs_init_inodecache(void)
{}

static void nfs_destroy_inodecache(void)
{}

struct workqueue_struct *nfsiod_workqueue;
EXPORT_SYMBOL_GPL();

/*
 * start up the nfsiod workqueue
 */
static int nfsiod_start(void)
{}

/*
 * Destroy the nfsiod workqueue
 */
static void nfsiod_stop(void)
{}

unsigned int nfs_net_id;
EXPORT_SYMBOL_GPL();

static int nfs_net_init(struct net *net)
{}

static void nfs_net_exit(struct net *net)
{}

static struct pernet_operations nfs_net_ops =;

/*
 * Initialize NFS
 */
static int __init init_nfs_fs(void)
{}

static void __exit exit_nfs_fs(void)
{}

/* Not quite true; I just maintain it */
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();
module_param(enable_ino64, bool, 0644);

module_init()
module_exit()