linux/fs/nfs/nfs4state.c

/*
 *  fs/nfs/nfs4state.c
 *
 *  Client-side XDR for NFSv4.
 *
 *  Copyright (c) 2002 The Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  Kendrick Smith <[email protected]>
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the University nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Implementation of the NFSv4 state model.  For the time being,
 * this is minimal, but will be made much more complex in a
 * subsequent patch.
 */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/nfs_fs.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/ratelimit.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/sched/mm.h>

#include <linux/sunrpc/clnt.h>

#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
#include "internal.h"
#include "nfs4idmap.h"
#include "nfs4session.h"
#include "pnfs.h"
#include "netns.h"
#include "nfs4trace.h"

#define NFSDBG_FACILITY

#define OPENOWNER_POOL_SIZE

static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp);

const nfs4_stateid zero_stateid =;
const nfs4_stateid invalid_stateid =;

const nfs4_stateid current_stateid =;

static DEFINE_MUTEX(nfs_clid_init_mutex);

static int nfs4_setup_state_renewal(struct nfs_client *clp)
{}

int nfs4_init_clientid(struct nfs_client *clp, const struct cred *cred)
{}

/**
 * nfs40_discover_server_trunking - Detect server IP address trunking (mv0)
 *
 * @clp: nfs_client under test
 * @result: OUT: found nfs_client, or clp
 * @cred: credential to use for trunking test
 *
 * Returns zero, a negative errno, or a negative NFS4ERR status.
 * If zero is returned, an nfs_client pointer is planted in
 * "result".
 *
 * Note: The returned client may not yet be marked ready.
 */
int nfs40_discover_server_trunking(struct nfs_client *clp,
				   struct nfs_client **result,
				   const struct cred *cred)
{}

const struct cred *nfs4_get_machine_cred(struct nfs_client *clp)
{}

static void nfs4_root_machine_cred(struct nfs_client *clp)
{}

static const struct cred *
nfs4_get_renew_cred_server_locked(struct nfs_server *server)
{}

/**
 * nfs4_get_renew_cred - Acquire credential for a renew operation
 * @clp: client state handle
 *
 * Returns an rpc_cred with reference count bumped, or NULL.
 * Caller must hold clp->cl_lock.
 */
const struct cred *nfs4_get_renew_cred(struct nfs_client *clp)
{}

static void nfs4_end_drain_slot_table(struct nfs4_slot_table *tbl)
{}

static void nfs4_end_drain_session(struct nfs_client *clp)
{}

static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl)
{}

static int nfs4_begin_drain_session(struct nfs_client *clp)
{}

#if defined(CONFIG_NFS_V4_1)

static void nfs41_finish_session_reset(struct nfs_client *clp)
{}

int nfs41_init_clientid(struct nfs_client *clp, const struct cred *cred)
{}

/**
 * nfs41_discover_server_trunking - Detect server IP address trunking (mv1)
 *
 * @clp: nfs_client under test
 * @result: OUT: found nfs_client, or clp
 * @cred: credential to use for trunking test
 *
 * Returns NFS4_OK, a negative errno, or a negative NFS4ERR status.
 * If NFS4_OK is returned, an nfs_client pointer is planted in
 * "result".
 *
 * Note: The returned client may not yet be marked ready.
 */
int nfs41_discover_server_trunking(struct nfs_client *clp,
				   struct nfs_client **result,
				   const struct cred *cred)
{}

#endif /* CONFIG_NFS_V4_1 */

/**
 * nfs4_get_clid_cred - Acquire credential for a setclientid operation
 * @clp: client state handle
 *
 * Returns a cred with reference count bumped, or NULL.
 */
const struct cred *nfs4_get_clid_cred(struct nfs_client *clp)
{}

static struct nfs4_state_owner *
nfs4_find_state_owner_locked(struct nfs_server *server, const struct cred *cred)
{}

static struct nfs4_state_owner *
nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
{}

static void
nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
{}

static void
nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
{}

static void
nfs4_destroy_seqid_counter(struct nfs_seqid_counter *sc)
{}

/*
 * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to
 * create a new state_owner.
 *
 */
static struct nfs4_state_owner *
nfs4_alloc_state_owner(struct nfs_server *server,
		const struct cred *cred,
		gfp_t gfp_flags)
{}

static void
nfs4_reset_state_owner(struct nfs4_state_owner *sp)
{}

static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
{}

static void nfs4_gc_state_owners(struct nfs_server *server)
{}

/**
 * nfs4_get_state_owner - Look up a state owner given a credential
 * @server: nfs_server to search
 * @cred: RPC credential to match
 * @gfp_flags: allocation mode
 *
 * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL.
 */
struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
					      const struct cred *cred,
					      gfp_t gfp_flags)
{}

/**
 * nfs4_put_state_owner - Release a nfs4_state_owner
 * @sp: state owner data to release
 *
 * Note that we keep released state owners on an LRU
 * list.
 * This caches valid state owners so that they can be
 * reused, to avoid the OPEN_CONFIRM on minor version 0.
 * It also pins the uniquifier of dropped state owners for
 * a while, to ensure that those state owner names are
 * never reused.
 */
void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{}

/**
 * nfs4_purge_state_owners - Release all cached state owners
 * @server: nfs_server with cached state owners to release
 * @head: resulting list of state owners
 *
 * Called at umount time.  Remaining state owners will be on
 * the LRU with ref count of zero.
 * Note that the state owners are not freed, but are added
 * to the list @head, which can later be used as an argument
 * to nfs4_free_state_owners.
 */
void nfs4_purge_state_owners(struct nfs_server *server, struct list_head *head)
{}

/**
 * nfs4_free_state_owners - Release all cached state owners
 * @head: resulting list of state owners
 *
 * Frees a list of state owners that was generated by
 * nfs4_purge_state_owners
 */
void nfs4_free_state_owners(struct list_head *head)
{}

static struct nfs4_state *
nfs4_alloc_open_state(void)
{}

void
nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
{}

static struct nfs4_state *
__nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
{}

static void
nfs4_free_open_state(struct nfs4_state *state)
{}

struct nfs4_state *
nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner)
{}

void nfs4_put_open_state(struct nfs4_state *state)
{}

/*
 * Close the current file.
 */
static void __nfs4_close(struct nfs4_state *state,
		fmode_t fmode, gfp_t gfp_mask, int wait)
{}

void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
{}

void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
{}

/*
 * Search the state->lock_states for an existing lock_owner
 * that is compatible with either of the given owners.
 * If the second is non-zero, then the first refers to a Posix-lock
 * owner (current->files) and the second refers to a flock/OFD
 * owner (struct file*).  In that case, prefer a match for the first
 * owner.
 * If both sorts of locks are held on the one file we cannot know
 * which stateid was intended to be used, so a "correct" choice cannot
 * be made.  Failing that, a "consistent" choice is preferable.  The
 * consistent choice we make is to prefer the first owner, that of a
 * Posix lock.
 */
static struct nfs4_lock_state *
__nfs4_find_lock_state(struct nfs4_state *state,
		       fl_owner_t owner, fl_owner_t owner2)
{}

/*
 * Return a compatible lock_state. If no initialized lock_state structure
 * exists, return an uninitialized one.
 *
 */
static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t owner)
{}

void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
{}

/*
 * Return a compatible lock_state. If no initialized lock_state structure
 * exists, return an uninitialized one.
 *
 */
static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner)
{}

/*
 * Release reference to lock_state, and free it if we see that
 * it is no longer in use
 */
void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
{}

static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
{}

static void nfs4_fl_release_lock(struct file_lock *fl)
{}

static const struct file_lock_operations nfs4_fl_lock_ops =;

int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
{}

static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
		struct nfs4_state *state,
		const struct nfs_lock_context *l_ctx)
{}

bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
{}

/*
 * Byte-range lock aware utility to initialize the stateid of read/write
 * requests.
 */
int nfs4_select_rw_stateid(struct nfs4_state *state,
		fmode_t fmode, const struct nfs_lock_context *l_ctx,
		nfs4_stateid *dst, const struct cred **cred)
{}

struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
{}

void nfs_release_seqid(struct nfs_seqid *seqid)
{}

void nfs_free_seqid(struct nfs_seqid *seqid)
{}

/*
 * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
 * failed with a seqid incrementing error -
 * see comments nfs4.h:seqid_mutating_error()
 */
static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
{}

void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
{}

/*
 * Increment the seqid if the LOCK/LOCKU succeeded, or
 * failed with a seqid incrementing error -
 * see comments nfs4.h:seqid_mutating_error()
 */
void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
{}

int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
{}

static int nfs4_run_state_manager(void *);

static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
{}

/*
 * Schedule the nfs_client asynchronous state management routine
 */
void nfs4_schedule_state_manager(struct nfs_client *clp)
{}

/*
 * Schedule a lease recovery attempt
 */
void nfs4_schedule_lease_recovery(struct nfs_client *clp)
{}
EXPORT_SYMBOL_GPL();

/**
 * nfs4_schedule_migration_recovery - trigger migration recovery
 *
 * @server: FSID that is migrating
 *
 * Returns zero if recovery has started, otherwise a negative NFS4ERR
 * value is returned.
 */
int nfs4_schedule_migration_recovery(const struct nfs_server *server)
{}
EXPORT_SYMBOL_GPL();

/**
 * nfs4_schedule_lease_moved_recovery - start lease-moved recovery
 *
 * @clp: server to check for moved leases
 *
 */
void nfs4_schedule_lease_moved_recovery(struct nfs_client *clp)
{}
EXPORT_SYMBOL_GPL();

int nfs4_wait_clnt_recover(struct nfs_client *clp)
{}

int nfs4_client_recover_expired_lease(struct nfs_client *clp)
{}

/*
 * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
 * @clp: client to process
 *
 * Set the NFS4CLNT_LEASE_EXPIRED state in order to force a
 * resend of the SETCLIENTID and hence re-establish the
 * callback channel. Then return all existing delegations.
 */
static void nfs40_handle_cb_pathdown(struct nfs_client *clp)
{}

void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
{}

static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
{}

int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
{}

int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state)
{}
EXPORT_SYMBOL_GPL();

static struct nfs4_lock_state *
nfs_state_find_lock_state_by_stateid(struct nfs4_state *state,
		const nfs4_stateid *stateid)
{}

static bool nfs_state_lock_state_matches_stateid(struct nfs4_state *state,
		const nfs4_stateid *stateid)
{}

void nfs_inode_find_state_and_recover(struct inode *inode,
		const nfs4_stateid *stateid)
{}

static void nfs4_state_mark_open_context_bad(struct nfs4_state *state, int err)
{}

static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error)
{}


static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
{}

#ifdef CONFIG_NFS_V4_2
static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state *state)
{}
#else /* !CONFIG_NFS_V4_2 */
static inline void nfs42_complete_copies(struct nfs4_state_owner *sp,
					 struct nfs4_state *state)
{
}
#endif /* CONFIG_NFS_V4_2 */

static int __nfs4_reclaim_open_state(struct nfs4_state_owner *sp, struct nfs4_state *state,
				     const struct nfs4_state_recovery_ops *ops,
				     int *lost_locks)
{}

static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp,
				   const struct nfs4_state_recovery_ops *ops,
				   int *lost_locks)
{}

static void nfs4_clear_open_state(struct nfs4_state *state)
{}

static void nfs4_reset_seqids(struct nfs_server *server,
	int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
{}

static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp,
	int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
{}

static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp)
{}

static int nfs4_reclaim_complete(struct nfs_client *clp,
				 const struct nfs4_state_recovery_ops *ops,
				 const struct cred *cred)
{}

static void nfs4_clear_reclaim_server(struct nfs_server *server)
{}

static int nfs4_state_clear_reclaim_reboot(struct nfs_client *clp)
{}

static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
{}

static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
{}

static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
{}

static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
{}

static int nfs4_check_lease(struct nfs_client *clp)
{}

/* Set NFS4CLNT_LEASE_EXPIRED and reclaim reboot state for all v4.0 errors
 * and for recoverable errors on EXCHANGE_ID for v4.1
 */
static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
{}

static int nfs4_establish_lease(struct nfs_client *clp)
{}

/*
 * Returns zero or a negative errno.  NFS4ERR values are converted
 * to local errno values.
 */
static int nfs4_reclaim_lease(struct nfs_client *clp)
{}

static int nfs4_purge_lease(struct nfs_client *clp)
{}

/*
 * Try remote migration of one FSID from a source server to a
 * destination server.  The source server provides a list of
 * potential destinations.
 *
 * Returns zero or a negative NFS4ERR status code.
 */
static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred)
{}

/*
 * Returns zero or a negative NFS4ERR status code.
 */
static int nfs4_handle_migration(struct nfs_client *clp)
{}

/*
 * Test each nfs_server on the clp's cl_superblocks list to see
 * if it's moved to another server.  Stop when the server no longer
 * returns NFS4ERR_LEASE_MOVED.
 */
static int nfs4_handle_lease_moved(struct nfs_client *clp)
{}

/**
 * nfs4_discover_server_trunking - Detect server IP address trunking
 *
 * @clp: nfs_client under test
 * @result: OUT: found nfs_client, or clp
 *
 * Returns zero or a negative errno.  If zero is returned,
 * an nfs_client pointer is planted in "result".
 *
 * Note: since we are invoked in process context, and
 * not from inside the state manager, we cannot use
 * nfs4_handle_reclaim_lease_error().
 */
int nfs4_discover_server_trunking(struct nfs_client *clp,
				  struct nfs_client **result)
{}

#ifdef CONFIG_NFS_V4_1
void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
{}
EXPORT_SYMBOL_GPL();

void nfs41_notify_server(struct nfs_client *clp)
{}

static void nfs4_reset_all_state(struct nfs_client *clp)
{}

static void nfs41_handle_server_reboot(struct nfs_client *clp)
{}

static void nfs41_handle_all_state_revoked(struct nfs_client *clp)
{}

static void nfs41_handle_some_state_revoked(struct nfs_client *clp)
{}

static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
{}

static void nfs41_handle_backchannel_fault(struct nfs_client *clp)
{}

static void nfs41_handle_cb_path_down(struct nfs_client *clp)
{}

void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags,
		bool recovery)
{}

static int nfs4_reset_session(struct nfs_client *clp)
{}

static int nfs4_bind_conn_to_session(struct nfs_client *clp)
{}

static void nfs4_layoutreturn_any_run(struct nfs_client *clp)
{}
#else /* CONFIG_NFS_V4_1 */
static int nfs4_reset_session(struct nfs_client *clp) { return 0; }

static int nfs4_bind_conn_to_session(struct nfs_client *clp)
{
	return 0;
}

static void nfs4_layoutreturn_any_run(struct nfs_client *clp)
{
}
#endif /* CONFIG_NFS_V4_1 */

static void nfs4_state_manager(struct nfs_client *clp)
{}

static int nfs4_run_state_manager(void *ptr)
{}