| /* |
| * |
| * |
| * Copyright CEA/DAM/DIF (2008) |
| * contributeur : Philippe DENIEL philippe.deniel@cea.fr |
| * Thomas LEIBOVICI thomas.leibovici@cea.fr |
| * |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public License |
| * as published by the Free Software Foundation; either version 3 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301 USA |
| * |
| * --------------------------------------- |
| */ |
| |
| /** |
| * @defgroup SAL State abstraction layer |
| * @{ |
| */ |
| |
| /** |
| * @file sal_data.h |
| * @brief Data structures for state management. |
| */ |
| |
| #ifndef SAL_DATA_H |
| #define SAL_DATA_H |
| |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/param.h> |
| #include <time.h> |
| #include <pthread.h> |
| #include <dirent.h> /* For having MAXNAMLEN */ |
| |
| #include "abstract_atomic.h" |
| #include "abstract_mem.h" |
| #include "hashtable.h" |
| #include "fsal_pnfs.h" |
| #include "config_parsing.h" |
| |
| #ifdef _USE_9P |
| /* define u32 and related types independent of SAL and 9P */ |
| #include "9p_types.h" |
| #endif /* _USE_9P */ |
| |
| /** |
| ** Forward declarations to avoid circular dependency conflicts |
| */ |
| |
| #include "gsh_status.h" |
| |
| typedef struct nfs_client_id_t nfs_client_id_t; |
| typedef struct nfs41_session nfs41_session_t; |
| |
| /** |
| ** Consolidated circular dependencies |
| */ |
| |
| #include "nfs_proto_data.h" |
| |
| /** |
| ** Forward references to types |
| */ |
| typedef struct nfs_argop4_state nfs_argop4_state; |
| typedef struct nfs_client_record_t nfs_client_record_t; |
| typedef struct state_async_queue_t state_async_queue_t; |
| typedef struct state_block_data_t state_block_data_t; |
| typedef struct state_cookie_entry_t state_cookie_entry_t; |
| typedef struct state_lock_entry_t state_lock_entry_t; |
| typedef struct state_nfs4_owner_t state_nfs4_owner_t; |
| typedef struct state_nlm_client_t state_nlm_client_t; |
| typedef struct state_owner_t state_owner_t; |
| typedef struct state_t state_t; |
| |
| /** |
| * @brief Number of errors before giving up on recovery |
| * |
| * We set a maximum because the recovery routines need to terminate at |
| * some point. |
| */ |
| #define STATE_ERR_MAX 100 |
| |
| /** |
| * @brief Indicate that lock extends to the entire range of the file |
| * |
| * This is true no matter what the beginning of the lock range is. |
| */ |
| #define STATE_LOCK_OFFSET_EOF 0xFFFFFFFFFFFFFFFFLL |
| |
| extern struct fridgethr *state_async_fridge; |
| |
| /***************************************************************************** |
| * |
| * NFSv4.1 Session data |
| * |
| *****************************************************************************/ |
| |
| extern pool_t *nfs41_session_pool; |
| |
| /** |
| * @param Session ID hash |
| */ |
| |
| extern hash_table_t *ht_session_id; |
| |
| /** |
| * @brief Number of forechannel slots in a session |
| * |
| * This is also the maximum number of backchannel slots we'll use, |
| * even if the client offers more. |
| */ |
| #define NFS41_NB_SLOTS 3 |
| |
| /** |
| * @brief Members in the slot table |
| */ |
| |
| typedef struct nfs41_session_slot__ { |
| sequenceid4 sequence; /*< Sequence number of this operation */ |
| pthread_mutex_t lock; /*< Lock on the slot */ |
| struct COMPOUND4res_extended cached_result; /*< NFv41: pointer to |
| cached RPC result in |
| a session's slot */ |
| unsigned int cache_used; /*< If we cached the result */ |
| } nfs41_session_slot_t; |
| |
| /** |
| * @brief Bookkeeping for callback slots on the client |
| */ |
| |
| typedef struct nfs41_cb_session_slot { |
| sequenceid4 sequence; /*< Sequence number of last call */ |
| bool in_use; /*< Set if a call if in progress on this slot */ |
| } nfs41_cb_session_slot_t; |
| |
| /** |
| * Flag indicating that the backchannel is up |
| */ |
| enum { |
| session_bc_up = 0x01, |
| session_bc_fault = 0x02, /* not actually used anywhere */ |
| }; |
| |
| /** |
| * @brief Structure representing an NFSv4.1 session |
| */ |
| |
| struct nfs41_session { |
| char session_id[NFS4_SESSIONID_SIZE]; /*< Session ID */ |
| int32_t refcount; |
| clientid4 clientid; /*< Clientid owning this session */ |
| nfs_client_id_t *clientid_record; /*< Client record |
| correspinding to ID */ |
| struct glist_head session_link; /*< Link in the list of |
| sessions for this |
| clientid */ |
| uint32_t flags; /*< Flags pertaining to this session */ |
| SVCXPRT *xprt; /*< Referenced pointer to transport */ |
| |
| channel_attrs4 fore_channel_attrs; /*< Fore-channel attributes */ |
| nfs41_session_slot_t slots[NFS41_NB_SLOTS]; /*< Slot table */ |
| |
| channel_attrs4 back_channel_attrs; /*< Back-channel attributes */ |
| nfs41_cb_session_slot_t cb_slots[NFS41_NB_SLOTS]; /*< Callback |
| Slot table */ |
| uint32_t cb_program; /*< Callback program ID */ |
| struct rpc_call_channel cb_chan; /*< Back channel */ |
| pthread_mutex_t cb_mutex; /*< Protects the cb slot table, |
| when searching for a free slot */ |
| pthread_cond_t cb_cond; /*< Condition variable on which we |
| wait if the slot table is full |
| and on which we signal when we |
| free an entry. */ |
| }; |
| |
| /** |
| * @brief Track the call that creates a state, for NFSv4.1. |
| */ |
| |
| struct state_refer { |
| sessionid4 session; /*< The session of the creating call. */ |
| sequenceid4 sequence; /*< The sequence ID of the creating |
| call. */ |
| slotid4 slot; /*< The slot ID of the creating call. */ |
| }; |
| |
| /****************************************************************************** |
| * |
| * NFSv4 Recovery data |
| * |
| *****************************************************************************/ |
| |
| /** |
| * @brief Revoked filehandle list |
| */ |
| typedef struct rdel_fh { |
| struct glist_head rdfh_list; |
| char *rdfh_handle_str; |
| } rdel_fh_t; |
| |
| /** |
| * @brief A client entry |
| */ |
| typedef struct clid_entry { |
| struct glist_head cl_list; /*< Link in the list */ |
| struct glist_head cl_rfh_list; |
| char cl_name[PATH_MAX]; /*< Client name */ |
| } clid_entry_t; |
| |
| extern char v4_old_dir[PATH_MAX]; |
| extern char v4_recov_dir[PATH_MAX]; |
| |
| /****************************************************************************** |
| * |
| * NFSv4 State data |
| * |
| *****************************************************************************/ |
| |
| extern hash_table_t *ht_state_id; |
| |
| #include "sal_shared.h" |
| |
| /** |
| * @brief Data for an NFS v4 share reservation/open |
| */ |
| |
| struct state_share { |
| struct glist_head share_lockstates; /*< Lock states for this |
| open state |
| This field MUST be first */ |
| unsigned int share_access; /*< The NFSv4 Share Access state */ |
| unsigned int share_deny; /*< The NFSv4 Share Deny state */ |
| unsigned int share_access_prev; /*< Previous share access state */ |
| unsigned int share_deny_prev; /*< Previous share deny state */ |
| }; |
| |
| /** |
| * @brief Data for an NLM share reservation/open |
| */ |
| |
| struct state_nlm_share { |
| struct glist_head share_perclient; /*< Lock states for this |
| open state |
| This field MUST be first */ |
| unsigned int share_access; /*< The NFSv4 Share Access state */ |
| unsigned int share_deny; /*< The NFSv4 Share Deny state */ |
| unsigned int share_access_prev; /*< Previous share access state */ |
| unsigned int share_deny_prev; /*< Previous share deny state */ |
| }; |
| |
| /** |
| * @brief Data for a set of locks |
| */ |
| |
| struct state_lock { |
| struct glist_head state_locklist; /*< List of locks owned by |
| this stateid |
| This field MUST be first */ |
| struct glist_head state_sharelist; /*< List of states related |
| to a share */ |
| state_t *openstate; /*< The related open-state */ |
| }; |
| |
| /** |
| * @brief Data for a 9p fid |
| */ |
| |
| struct state_9p_fid { |
| struct glist_head state_locklist; /*< List of locks owned by |
| this fid |
| This field MUST be first */ |
| unsigned int share_access; /*< The 9p Access state */ |
| unsigned int share_deny; /*< Will always be 0 */ |
| }; |
| |
| /** |
| * @brief Stats for client-file delegation heuristics |
| */ |
| |
| /* @brief Per client, per file stats */ |
| struct cf_deleg_stats { |
| time_t cfd_rs_time; /* time when the client responsed |
| NFS4_OK for a recall. */ |
| time_t cfd_r_time; /* time of the recall attempt */ |
| }; |
| |
| /** |
| * @brief States of a delegation |
| * |
| * Different states a delegation can be in during its lifetime |
| */ |
| enum deleg_state { |
| DELEG_GRANTED = 1, /* Granted */ |
| DELEG_RECALL_WIP, /* Recall in progress */ |
| }; |
| |
| /** |
| * @brief Data for a delegation |
| */ |
| |
| struct state_deleg { |
| open_delegation_type4 sd_type; |
| time_t sd_grant_time; /* time of successful delegation */ |
| enum deleg_state sd_state; |
| struct cf_deleg_stats sd_clfile_stats; /* client specific */ |
| }; |
| |
| /** |
| * @brief Data for a set of layouts of a given type |
| */ |
| |
| struct state_layout { |
| struct glist_head state_segments; /*< List of segments */ |
| layouttype4 state_layout_type; /*< The type of layout this state |
| represents */ |
| uint32_t granting; /*< Number of LAYOUTGETs in progress */ |
| bool state_return_on_close; /*< Whether this layout should be |
| returned on last close. */ |
| }; |
| |
| /** |
| * @brief Type specific state data |
| */ |
| |
| union state_data { |
| struct state_share share; |
| struct state_nlm_share nlm_share; |
| struct state_lock lock; |
| struct state_deleg deleg; |
| struct state_layout layout; |
| struct state_9p_fid fid; |
| uint32_t io_advise; |
| }; |
| |
| /** |
| * @brief The number of bytes in the stateid.other |
| * |
| * The value 12 is fixed by RFC 3530/RFC 5661. |
| */ |
| #define OTHERSIZE 12 |
| |
| extern char all_zero[OTHERSIZE]; |
| extern char all_ones[OTHERSIZE]; |
| |
| struct state_obj { |
| char digest[58]; |
| size_t len; |
| }; |
| |
| /** |
| * @brief Structure representing a single NFSv4 state |
| * |
| * Each state is identified by stateid and represents some resource or |
| * set of resources. |
| * |
| * The lists are protected by the state_lock |
| */ |
| |
| struct state_t { |
| struct glist_head state_list; /**< List of states on a file */ |
| struct glist_head state_owner_list; /**< List of states for an owner */ |
| struct glist_head state_export_list; /**< List of states on the same |
| export */ |
| #ifdef DEBUG_SAL |
| struct glist_head state_list_all; /**< Global list of all stateids */ |
| #endif |
| pthread_mutex_t state_mutex; /**< Mutex protecting following pointers */ |
| struct gsh_export *state_export; /**< Export this entry belongs to */ |
| /* Don't re-order or move these next two. They are used for hashing */ |
| state_owner_t *state_owner; /**< State Owner related to state */ |
| struct state_obj state_obj; /**< digest of owning object */ |
| struct fsal_export *state_exp; /**< FSAL export */ |
| union state_data state_data; |
| enum state_type state_type; |
| u_int32_t state_seqid; /**< The NFSv4 Sequence id */ |
| int32_t state_refcount; /**< Refcount for state_t objects */ |
| char stateid_other[OTHERSIZE]; /**< "Other" part of state id, |
| used as hash key */ |
| struct state_refer state_refer; /**< For NFSv4.1, track the |
| call that created a |
| state. */ |
| }; |
| |
| /* Macros to compare and copy state_t to a struct stateid4 */ |
| #define SAME_STATEID(id4, state) \ |
| ((id4)->seqid == (state)->state_seqid && \ |
| memcmp((id4)->other, (state)->stateid_other, OTHERSIZE) == 0) |
| |
| #define COPY_STATEID(id4, state) \ |
| do { \ |
| (id4)->seqid = (state)->state_seqid; \ |
| (void)memcpy((id4)->other, (state)->stateid_other, OTHERSIZE); \ |
| } while (0) |
| |
| /***************************************************************************** |
| * |
| * NFS Owner data |
| * |
| *****************************************************************************/ |
| |
| typedef void (state_owner_init_t) (state_owner_t *powner); |
| |
| extern hash_table_t *ht_nlm_owner; |
| #ifdef _USE_9P |
| extern hash_table_t *ht_9p_owner; |
| #endif |
| extern hash_table_t *ht_nfs4_owner; |
| |
| extern struct glist_head cached_open_owners; |
| extern pthread_mutex_t cached_open_owners_lock; |
| |
| /** |
| * @brief A structure identifying the owner of an NFSv4 open or lock state |
| * |
| * This serves as the key to the NFSv4 owner table, and is generated |
| * from either an open or lock owner. |
| */ |
| |
| typedef struct state_nfs4_owner_name_t { |
| unsigned int son_owner_len; |
| char *son_owner_val; |
| } state_nfs4_owner_name_t; |
| |
| /** |
| * @brief The type of entity responsible for a state |
| * |
| * For NLM and 9P, one kind of owner owns every kind of state. For |
| * NFSv4.1 open owners and lock owners are in disjoint spaces, and all |
| * non-open and non-lock states are associated with a given client. |
| */ |
| |
| typedef enum state_owner_type_t { |
| STATE_LOCK_OWNER_UNKNOWN, /*< Unknown */ |
| #ifdef _USE_NLM |
| STATE_LOCK_OWNER_NLM, /*< An NLM client */ |
| #endif /* _USE_NLM */ |
| #ifdef _USE_9P |
| STATE_LOCK_OWNER_9P, /*< A 9P client */ |
| #endif |
| STATE_OPEN_OWNER_NFSV4, /*< An NFSv4 owner of an open */ |
| STATE_LOCK_OWNER_NFSV4, /*< An NFSv4 owner of a set of locks */ |
| STATE_CLIENTID_OWNER_NFSV4 /*< An NFSv4 client, owns all |
| states but opens and locks. */ |
| } state_owner_type_t; |
| |
| /** |
| * @brief Specifies interest in a client for NLN/NSM. |
| */ |
| |
| typedef enum care_t { |
| CARE_NOT, /*< Do not care about client's status */ |
| CARE_ALWAYS, /*< Always care about client's status */ |
| CARE_NO_MONITOR, /*< Care, but will not actively monitor */ |
| CARE_MONITOR /*< Will actively monitor client status */ |
| } care_t; |
| |
| extern hash_table_t *ht_nsm_client; |
| extern hash_table_t *ht_nlm_client; |
| |
| /** |
| * @brief NSM (rpc.statd) state for a given client. |
| */ |
| |
| typedef struct state_nsm_client_t { |
| pthread_mutex_t ssc_mutex; /*< Mutex protecting this |
| structure */ |
| struct glist_head ssc_lock_list; /*< All locks held by client */ |
| struct glist_head ssc_share_list; /*< All share reservations */ |
| struct gsh_client *ssc_client; /*< The client involved */ |
| int32_t ssc_refcount; /*< Reference count to protect |
| structure */ |
| int32_t ssc_monitored; /*< If this client is actively |
| monitored */ |
| int32_t ssc_nlm_caller_name_len; /*< Length of identifier */ |
| char *ssc_nlm_caller_name; /*< Client identifier */ |
| } state_nsm_client_t; |
| |
| /** |
| * @brief Represent a single client accessing us through NLM |
| */ |
| |
| struct state_nlm_client_t { |
| state_nsm_client_t *slc_nsm_client; /*< Related NSM client */ |
| xprt_type_t slc_client_type; /*< The transport type to this |
| client */ |
| int32_t slc_refcount; /*< Reference count for disposal */ |
| struct sockaddr_storage slc_server_addr; /*< local addr when request is |
| made */ |
| int32_t slc_nlm_caller_name_len; /*< Length of client name */ |
| char *slc_nlm_caller_name; /*< Client name */ |
| CLIENT *slc_callback_clnt; /*< Callback for blocking locks */ |
| AUTH *slc_callback_auth; /*< Authentication for callback */ |
| }; |
| |
| /** |
| * @brief Owner of an NLM lock or share. |
| */ |
| |
| typedef struct state_nlm_owner_t { |
| state_nlm_client_t *so_client; /*< Structure for this client */ |
| int32_t so_nlm_svid; /*< Owner within client */ |
| struct glist_head so_nlm_shares; /*< Share reservations */ |
| } state_nlm_owner_t; |
| |
| /** |
| * @brief 9P lock owner |
| */ |
| |
| #ifdef _USE_9P |
| typedef struct state_9p_owner_t { |
| u32 proc_id; /*< PID on the client */ |
| struct sockaddr_storage client_addr; /*< Network address of client */ |
| } state_9p_owner_t; |
| #endif /* _USE_9P */ |
| |
| /** |
| * @brief Share and lock operations for NFSv4.0 |
| * |
| * This structure saves the arguments to the most recent operation on |
| * an open or lock owner associated with an NFSv4.0 client. This is |
| * part of the At-Most Once semantics and not used under NFSv4.1. |
| */ |
| |
| struct nfs_argop4_state { |
| nfs_opnum4 argop; /*< Operation being saved */ |
| union { |
| CLOSE4args opclose; /*< CLOSE */ |
| LOCK4args oplock; /*< LOCK */ |
| LOCKU4args oplocku; /*< LOCKU */ |
| OPEN4args opopen; /*< OPEN */ |
| OPEN_CONFIRM4args opopen_confirm; /*< OPEN_CONFIRM */ |
| OPEN_DOWNGRADE4args opopen_downgrade; /*< OPEN_DOWNGRADE */ |
| } nfs_argop4_u; |
| }; |
| |
| /** |
| * @brief A structure supporting all NFSv4 owners. |
| */ |
| |
| struct state_nfs4_owner_t { |
| clientid4 so_clientid; /*< Owning clientid */ |
| nfs_client_id_t *so_clientrec; /*< Owning client id record */ |
| bool so_confirmed; /*< Confirmation (NFSv4.0 only) */ |
| seqid4 so_seqid; /*< Seqid for serialization of operations on |
| owner (NFSv4.0 only) */ |
| nfs_argop4_state so_args; /*< Saved args */ |
| void *so_last_entry; /*< Last file operated on by this state owner |
| * we don't keep a reference so this is a |
| * void * to prevent it's dereferencing because |
| * the pointer might become invalid if cache |
| * inode flushes the entry out. But it sufices |
| * for the purposes of detecting replayed |
| * operations. |
| */ |
| nfs_resop4 so_resp; /*< Saved response */ |
| state_owner_t *so_related_owner; /*< For lock-owners, the |
| open-owner under which |
| the lock owner was |
| created */ |
| struct glist_head so_state_list; /*< States owned by this owner */ |
| struct glist_head so_perclient; /*< open owner entry to be |
| linked to client */ |
| time_t cache_expire; /* time cached OPEN owner will expire */ |
| }; |
| |
| /** |
| * @brief General state owner |
| * |
| * This structure encodes the owner of any state, protocol specific |
| * information is contained within the union. |
| */ |
| |
| struct state_owner_t { |
| state_owner_type_t so_type; /*< Owner type */ |
| struct glist_head so_lock_list; /*< Locks for this owner */ |
| #ifdef DEBUG_SAL |
| struct glist_head so_all_owners; /**< Global list of all state owners */ |
| #endif /* _DEBUG_MEMLEAKS */ |
| pthread_mutex_t so_mutex; /*< Mutex on this owner */ |
| int32_t so_refcount; /*< Reference count for lifecyce management */ |
| int so_owner_len; /*< Length of owner name */ |
| char *so_owner_val; /*< Owner name */ |
| union { |
| state_nfs4_owner_t so_nfs4_owner; /*< All NFSv4 state owners */ |
| state_nlm_owner_t so_nlm_owner; /*< NLM lock and share |
| owners */ |
| #ifdef _USE_9P |
| state_9p_owner_t so_9p_owner; /*< 9P lock owners */ |
| #endif |
| } so_owner; |
| }; |
| |
| /* Test if the lock owner type is 9P */ |
| #ifdef _USE_9P |
| #define LOCK_OWNER_9P(owner) ((owner)->so_type == STATE_LOCK_OWNER_9P) |
| #else |
| #define LOCK_OWNER_9P(owner) (0) |
| #endif |
| |
| extern state_owner_t unknown_owner; |
| |
| /****************************************************************************** |
| * |
| * NFSv4 Clientid data |
| * |
| *****************************************************************************/ |
| |
| /** |
| * @brief State of a clientid record. |
| */ |
| |
| typedef enum nfs_clientid_confirm_state__ { |
| UNCONFIRMED_CLIENT_ID, |
| CONFIRMED_CLIENT_ID, |
| EXPIRED_CLIENT_ID, |
| STALE_CLIENT_ID |
| } nfs_clientid_confirm_state_t; |
| |
| /** |
| * @brief Errors from the clientid functions |
| */ |
| |
| typedef enum clientid_status { |
| CLIENT_ID_SUCCESS = 0, /*< Success */ |
| CLIENT_ID_INSERT_MALLOC_ERROR, /*< Unable to allocate memory */ |
| CLIENT_ID_INVALID_ARGUMENT, /*< Invalid argument */ |
| CLIENT_ID_EXPIRED, /*< requested client id expired */ |
| CLIENT_ID_STALE /*< requested client id stale */ |
| } clientid_status_t; |
| |
| /** |
| * @brief Record associated with a clientid |
| * |
| * This record holds Ganesha's state on an NFSv4.0 client. |
| */ |
| |
| struct nfs_client_id_t { |
| clientid4 cid_clientid; /*< The clientid */ |
| verifier4 cid_verifier; /*< Known verifier */ |
| verifier4 cid_incoming_verifier; /*< Most recently supplied verifier */ |
| time_t cid_last_renew; /*< Time of last renewal */ |
| nfs_clientid_confirm_state_t cid_confirmed; /*< Confirm/expire state */ |
| nfs_client_cred_t cid_credential; /*< Client credential */ |
| int cid_allow_reclaim; /*< Whether this client can still |
| reclaim state */ |
| char *cid_recov_dir; /*< Recovery directory */ |
| nfs_client_record_t *cid_client_record; /*< Record for managing |
| confirmation and |
| replacement */ |
| struct glist_head cid_openowners; /*< All open owners */ |
| struct glist_head cid_lockowners; /*< All lock owners */ |
| pthread_mutex_t cid_mutex; /*< Mutex for this client */ |
| union { |
| struct { |
| /** Callback channel */ |
| struct rpc_call_channel cb_chan; |
| /** Decoded address */ |
| gsh_addr_t cb_addr; |
| /** Callback identifier */ |
| uint32_t cb_callback_ident; |
| /** Universal address */ |
| char cb_client_r_addr[SOCK_NAME_MAX + 1]; |
| /** Callback program */ |
| uint32_t cb_program; |
| bool cb_chan_down; /* Callback channel state */ |
| } v40; /*< v4.0 callback information */ |
| struct { |
| bool cid_reclaim_complete; /*< reclaim complete |
| indication */ |
| /** All sessions */ |
| struct glist_head cb_session_list; |
| } v41; /*< v4.1 callback information */ |
| } cid_cb; /*< Version specific callback information */ |
| time_t first_path_down_resp_time; /* Time when the server first sent |
| NFS4ERR_CB_PATH_DOWN */ |
| char cid_server_owner[MAXNAMLEN + 1]; /*< Server owner. |
| * @note Why is this |
| * stored per-client? */ |
| char cid_server_scope[MAXNAMLEN + 1]; /*< Server scope */ |
| unsigned int cid_nb_session; /*< Number of sessions stored */ |
| nfs41_session_slot_t cid_create_session_slot; /*< Cached response to |
| last CREATE_SESSION */ |
| unsigned cid_create_session_sequence; /*< Sequence number for session |
| creation. */ |
| state_owner_t cid_owner; /*< Owner for per-client state */ |
| int32_t cid_refcount; /*< Reference count for lifecycle */ |
| int cid_lease_reservations; /*< Counted lease reservations, to spare |
| this clientid from the reaper */ |
| uint32_t cid_minorversion; |
| uint32_t cid_stateid_counter; |
| |
| uint32_t curr_deleg_grants; /* current num of delegations owned by |
| this client */ |
| uint32_t num_revokes; /* Num revokes for the client */ |
| struct gsh_client *gsh_client; /* for client specific statistics. */ |
| }; |
| |
| /** |
| * @brief Client owner record for verification and replacement |
| * |
| * @note The cr_mutex should never be acquired while holding a |
| * cid_mutex. |
| */ |
| |
| struct nfs_client_record_t { |
| int32_t cr_refcount; /*< Reference count for lifecycle */ |
| pthread_mutex_t cr_mutex; /*< Mutex protecting this structure */ |
| nfs_client_id_t *cr_confirmed_rec; /*< The confirmed record associated |
| with this owner (if there is |
| one.) */ |
| nfs_client_id_t *cr_unconfirmed_rec; /*< The unconfirmed record |
| associated with this |
| client name, if there is |
| one. */ |
| uint32_t cr_server_addr; /*< Server IP address the client connected to |
| */ |
| uint32_t cr_pnfs_flags; /*< pNFS flags. RFC 5661 allows us |
| to treat identical co_owners with |
| different pNFS flags as |
| disjoint. Linux client stupidity |
| forces us to do so. */ |
| int cr_client_val_len; /*< Length of owner */ |
| char cr_client_val[]; /*< Suplied co_owner */ |
| }; |
| |
| extern pool_t *client_id_pool; |
| |
| extern hash_table_t *ht_client_record; |
| extern hash_table_t *ht_confirmed_client_id; |
| extern hash_table_t *ht_unconfirmed_client_id; |
| |
| /****************************************************************************** |
| * |
| * Lock Data |
| * |
| *****************************************************************************/ |
| |
| /** |
| * @brief Blocking lock type and state |
| */ |
| |
| typedef enum state_blocking_t { |
| STATE_NON_BLOCKING, |
| STATE_NLM_BLOCKING, |
| STATE_NFSV4_BLOCKING, |
| STATE_GRANTING, |
| STATE_CANCELED |
| } state_blocking_t; |
| |
| /** |
| * @brief Grant callback |
| * |
| * The granted call back is responsible for acquiring a reference to |
| * the lock entry if needed. |
| */ |
| typedef state_status_t(*granted_callback_t) (struct fsal_obj_handle *obj, |
| state_lock_entry_t *lock_entry); |
| |
| /** |
| * @brief NLM specific Blocking lock data |
| */ |
| |
| typedef struct state_nlm_block_data_t { |
| netobj sbd_nlm_fh; /*< Filehandle */ |
| char sbd_nlm_fh_buf[NFS3_FHSIZE]; /*< Statically allocated |
| FH buffer */ |
| } state_nlm_block_data_t; |
| |
| extern struct glist_head state_blocked_locks; |
| |
| /** |
| * @brief Grant types |
| */ |
| typedef enum state_grant_type_t { |
| STATE_GRANT_NONE, /*< No grant */ |
| STATE_GRANT_INTERNAL, /*< Grant generated by SAL */ |
| STATE_GRANT_FSAL, /*< FSAL granting lock */ |
| STATE_GRANT_FSAL_AVAILABLE, /*< FSAL signalling lock availability */ |
| STATE_GRANT_POLL, /*< Poll this lock */ |
| } state_grant_type_t; |
| |
| typedef enum state_block_type_t { |
| /** Not blocking */ |
| STATE_BLOCK_NONE, |
| /** Lock is blocked by an internal lock. */ |
| STATE_BLOCK_INTERNAL, |
| /** Lock is blocked and FSAL supports async blocking locks. */ |
| STATE_BLOCK_ASYNC, |
| /** Lock is blocked and SAL will poll the lock. */ |
| STATE_BLOCK_POLL, |
| } state_block_type_t; |
| |
| /** |
| * @brief Blocking lock data |
| */ |
| struct state_block_data_t { |
| struct glist_head sbd_list; /*< Lost of blocking locks */ |
| state_grant_type_t sbd_grant_type; /*< Type of grant */ |
| state_block_type_t sbd_block_type; /*< Type of block */ |
| granted_callback_t sbd_granted_callback; /*< Callback for grant */ |
| state_cookie_entry_t *sbd_blocked_cookie; /*< Blocking lock cookie */ |
| state_lock_entry_t *sbd_lock_entry; /*< Details of lock */ |
| union { |
| state_nlm_block_data_t sbd_nlm; /*< NLM block data */ |
| void *sbd_v4; /*< NFSv4 block data */ |
| } sbd_prot; |
| }; |
| |
| struct state_lock_entry_t { |
| struct glist_head sle_list; /*< Locks on this file */ |
| struct glist_head sle_owner_locks; /*< Link on the owner lock list */ |
| struct glist_head sle_client_locks; /*< Locks on this client */ |
| struct glist_head sle_state_locks; /*< Locks on this state */ |
| #ifdef DEBUG_SAL |
| struct glist_head sle_all_locks; /*< Link on the global lock list */ |
| #endif /* DEBUG_SAL */ |
| struct glist_head sle_export_locks; /*< Link on the export |
| lock list */ |
| struct gsh_export *sle_export; |
| struct fsal_obj_handle *sle_obj; /*< File being locked */ |
| state_block_data_t *sle_block_data; /*< Blocking lock data */ |
| state_owner_t *sle_owner; /* Lock owner */ |
| state_t *sle_state; /*< Associated lock state */ |
| state_blocking_t sle_blocked; /*< Blocking status */ |
| int32_t sle_ref_count; /*< Reference count */ |
| fsal_lock_param_t sle_lock; /*< Lock description */ |
| pthread_mutex_t sle_mutex; /*< Mutex to protect the structure */ |
| }; |
| |
| /** |
| * @brief The ref counted share reservation state. |
| * |
| * Each field represents the count of instances of that flag being present |
| * in a v3 or v4 share reservation. |
| * |
| * There is a separate count of v4 deny write flags so that they can be |
| * enforced against v3 writes (v3 deny writes can not be enforced against |
| * v3 writes because there is no connection between the share reservation |
| * and the write operation). v3 reads will always be allowed. |
| */ |
| typedef struct sal_share__ { |
| unsigned int share_access_read; |
| unsigned int share_access_write; |
| unsigned int share_deny_read; |
| unsigned int share_deny_write; |
| unsigned int share_deny_write_v4; /**< Count of v4 share deny write */ |
| } sal_share_t; |
| |
| /** |
| * @brief Stats for file-specific and client-file delegation heuristics |
| */ |
| |
| struct file_deleg_stats { |
| uint32_t fds_curr_delegations; /* number of delegations on file */ |
| open_delegation_type4 fds_deleg_type; /* delegation type */ |
| uint32_t fds_delegation_count; /* times file has been delegated */ |
| uint32_t fds_recall_count; /* times file has been recalled */ |
| time_t fds_avg_hold; /* avg amount of time deleg held */ |
| time_t fds_last_delegation; |
| time_t fds_last_recall; |
| uint32_t fds_num_opens; /* total num of opens so far. */ |
| time_t fds_first_open; /* time that we started recording |
| num_opens */ |
| }; |
| |
| /** |
| * @brief Per-file state lists |
| * |
| * To be used by FSALs |
| */ |
| struct state_file { |
| /** File owning state */ |
| struct fsal_obj_handle *obj; |
| /** NFSv4 states on this file. Protected by state_lock */ |
| struct glist_head list_of_states; |
| /** Layout recalls on this file. Protected by state_lock */ |
| struct glist_head layoutrecall_list; |
| /** Pointers for lock list. Protected by state_lock */ |
| struct glist_head lock_list; |
| /** Pointers for NLM share list. Protected by state_lock */ |
| struct glist_head nlm_share_list; |
| /** Share reservation state for this file. Protected by state_lock */ |
| sal_share_t share_state; |
| bool write_delegated; /* true iff write delegated */ |
| /** Delegation statistics. Protected by state_lock */ |
| struct file_deleg_stats fdeleg_stats; |
| uint32_t anon_ops; /* number of anonymous operations |
| * happening at the moment which |
| * prevents delegations from being |
| * granted */ |
| }; |
| |
| /** |
| * @brief Per-directory state lists |
| * |
| * To be used by FSALs/SAL |
| */ |
| struct state_dir { |
| /** If this is a junction, the export this node points to. |
| * Protected by state_lock. */ |
| struct gsh_export *junction_export; |
| /** List of exports that have this cache inode as their root. |
| * Protected by state_lock */ |
| struct glist_head export_roots; |
| /** There is one export root reference counted for each export |
| for which this entry is a root for. This field is used |
| with the atomic inc/dec/fetch routines. */ |
| int32_t exp_root_refcount; |
| }; |
| |
| struct state_hdl { |
| /** Lock protecting state */ |
| pthread_rwlock_t state_lock; |
| bool no_cleanup; |
| union { |
| struct state_file file; |
| struct state_dir dir; |
| }; |
| }; |
| |
| /** |
| * @brief Description of a layout segment |
| */ |
| |
| typedef struct state_layout_segment { |
| struct glist_head sls_state_segments; /*< Link on the per-layout-state |
| segment list */ |
| state_t *sls_state; /*< Associated layout state */ |
| struct pnfs_segment sls_segment; /*< Segment descriptor */ |
| void *sls_fsal_data; /*< FSAL data */ |
| } state_layout_segment_t; |
| |
| /** |
| * @brief An entry in a list of states affected by a recall |
| * |
| * We make a non-intrusive list so that a state can be affected by any |
| * number of recalls. |
| */ |
| |
| struct recall_state_list { |
| struct glist_head link; /*< Link to the next layout state in the |
| queue */ |
| state_t *state; /*< State on which to recall */ |
| }; |
| |
| /** |
| * @brief Processing for a LAYOUTRECALL from the FSAL. |
| */ |
| |
| struct state_layout_recall_file { |
| struct glist_head entry_link; /*< List of recalls on a file */ |
| struct fsal_obj_handle *obj; /*< Related file */ |
| layouttype4 type; /*< Type of layout being recalled */ |
| struct pnfs_segment segment; /*< Segment to recall */ |
| struct glist_head state_list; /*< List of states affected by this |
| layout */ |
| void *recall_cookie; /*< Cookie returned to FSAL on return of last |
| segment satisfying the layout */ |
| }; |
| |
| /** |
| * @brief Blocking lock cookie entry |
| * |
| * Management of lce_refcount |
| * ========================== |
| * |
| * * state_add_grant_cookie |
| * |
| * creates a reference. |
| * |
| * * state_find_grant |
| * |
| * gets a reference |
| * |
| * * state_complete_grant |
| * |
| * always releases 1 reference it releases a 2nd reference when the |
| * call instance is the first to actually try and complete the grant |
| * |
| * * state_release_grant |
| * |
| * always releases 1 reference it releases a 2nd reference when the |
| * call instance is the first to actually try and release the grant |
| * |
| * * state_cancel_grant |
| * |
| * calls cancel_blocked_lock, which will release the initial |
| * reference |
| * |
| * * cancel_blocked_lock |
| * |
| * releases 1 reference if cookie exists called by |
| * state_cancel_grant also called by unlock, cancel, sm_notify |
| */ |
| |
| struct state_cookie_entry_t { |
| struct fsal_obj_handle *sce_obj; /*< Associated file */ |
| state_lock_entry_t *sce_lock_entry; /*< Associated lock */ |
| void *sce_cookie; /*< Cookie data */ |
| int sce_cookie_size; /*< Length of cookie */ |
| }; |
| |
| /* |
| * Structures for state async processing |
| * |
| */ |
| |
| /** |
| * @brief Asynchronous state function |
| */ |
| typedef void (state_async_func_t) (state_async_queue_t *arg); |
| |
| /** |
| * @brief Data for asynchronous NLM calls |
| */ |
| typedef struct state_nlm_async_data_t { |
| state_nlm_client_t *nlm_async_host; /*< The client */ |
| void *nlm_async_key; /*< Identifying key */ |
| union { |
| nfs_res_t nlm_async_res; /*< Asynchronous response */ |
| nlm4_testargs nlm_async_grant; /*< Arguments for grant */ |
| } nlm_async_args; |
| } state_nlm_async_data_t; |
| |
| /** |
| * @brief Asynchronous blocking lock data |
| */ |
| |
| typedef struct state_async_block_data_t { |
| state_lock_entry_t *state_async_lock_entry; /*< Associated lock */ |
| } state_async_block_data_t; |
| |
| /** |
| * @brief Queue of asynchronous events |
| */ |
| |
| struct state_async_queue_t { |
| struct glist_head state_async_glist; /*< List of events */ |
| state_async_func_t *state_async_func; /*< Processing function */ |
| union { |
| state_nlm_async_data_t state_nlm_async_data; /*< Data for |
| operation */ |
| void *state_no_data; /*< Dummy pointer */ |
| } state_async_data; |
| }; |
| |
| /** |
| * @brief Start of grace period |
| * |
| * @note This looks specific to SONAS and ought not to be in the top |
| * level SAL files. (The SAL needs more A to support this kind |
| * of thing.) |
| */ |
| |
| #define EVENT_JUST_GRACE 0 /* Just start grace period */ |
| #define EVENT_CLEAR_BLOCKED 1 /* Start grace period, and clear blocked locks |
| */ |
| #define EVENT_RELEASE_IP 2 /* Start grace period, clear blocked locks, |
| and release all locks */ |
| #define EVENT_UPDATE_CLIENTS 3 /* Start grace period, clear blocked locks, |
| release all locks, and update clients list. |
| */ |
| #define EVENT_TAKE_NODEID 4 /* Start grace period, clear blocked locks, |
| release all locks, and update clients using |
| node id. */ |
| #define EVENT_TAKE_IP 5 /* Start grace period, clear blocked locks, |
| release all locks, and update clients using |
| IP address. */ |
| |
| typedef struct nfs_grace_start { |
| int event; /*< Reason for grace period, see EVENT_nnn */ |
| int nodeid; /*< Node from which we are taking over */ |
| char *ipaddr; /*< IP of failed node */ |
| } nfs_grace_start_t; |
| |
| /* Memory pools */ |
| |
| extern pool_t *state_owner_pool; /*< Pool for NFSv4 files's open owner */ |
| |
| #ifdef DEBUG_SAL |
| extern struct glist_head state_v4_all; |
| extern struct glist_head state_owners_all; |
| #endif |
| |
| #endif /* SAL_DATA_H */ |
| /** @} */ |