summaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4session.h
blob: f703b755351bd8ad2217fb18009e93232f2ccc61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * fs/nfs/nfs4session.h
 *
 * Copyright (c) 2012 Trond Myklebust <Trond.Myklebust@netapp.com>
 *
 */
#ifndef __LINUX_FS_NFS_NFS4SESSION_H
#define __LINUX_FS_NFS_NFS4SESSION_H

/* maximum number of slots to use */
#define NFS4_DEF_SLOT_TABLE_SIZE (64U)
#define NFS4_MAX_SLOT_TABLE (1024U)
#define NFS4_NO_SLOT ((u32)-1)

#if IS_ENABLED(CONFIG_NFS_V4)

/* Sessions slot seqid */
struct nfs4_slot {
	struct nfs4_slot_table	*table;
	struct nfs4_slot	*next;
	unsigned long		generation;
	u32			slot_nr;
	u32		 	seq_nr;
	unsigned int		interrupted : 1,
				seq_done : 1;
};

/* Sessions */
enum nfs4_slot_tbl_state {
	NFS4_SLOT_TBL_DRAINING,
};

#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long))
struct nfs4_slot_table {
	struct nfs4_session *session;		/* Parent session */
	struct nfs4_slot *slots;		/* seqid per slot */
	unsigned long   used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
	spinlock_t	slot_tbl_lock;
	struct rpc_wait_queue	slot_tbl_waitq;	/* allocators may wait here */
	wait_queue_head_t	slot_waitq;	/* Completion wait on slot */
	u32		max_slots;		/* # slots in table */
	u32		max_slotid;		/* Max allowed slotid value */
	u32		highest_used_slotid;	/* sent to server on each SEQ.
						 * op for dynamic resizing */
	u32		target_highest_slotid;	/* Server max_slot target */
	u32		server_highest_slotid;	/* Server highest slotid */
	s32		d_target_highest_slotid; /* Derivative */
	s32		d2_target_highest_slotid; /* 2nd derivative */
	unsigned long	generation;		/* Generation counter for
						   target_highest_slotid */
	struct completion complete;
	unsigned long	slot_tbl_state;
};

/*
 * Session related parameters
 */
struct nfs4_session {
	struct nfs4_sessionid		sess_id;
	u32				flags;
	unsigned long			session_state;
	u32				hash_alg;
	u32				ssv_len;

	/* The fore and back channel */
	struct nfs4_channel_attrs	fc_attrs;
	struct nfs4_slot_table		fc_slot_table;
	struct nfs4_channel_attrs	bc_attrs;
	struct nfs4_slot_table		bc_slot_table;
	struct nfs_client		*clp;
};

enum nfs4_session_state {
	NFS4_SESSION_INITING,
	NFS4_SESSION_ESTABLISHED,
};

extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
		unsigned int max_reqs, const char *queue);
extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl);
extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl);
extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid);
extern int nfs4_slot_wait_on_seqid(struct nfs4_slot_table *tbl,
		u32 slotid, u32 seq_nr,
		unsigned long timeout);
extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl);
bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
		struct nfs4_slot *slot);
void nfs41_wake_slot_table(struct nfs4_slot_table *tbl);

static inline bool nfs4_slot_tbl_draining(struct nfs4_slot_table *tbl)
{
	return !!test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state);
}

static inline bool nfs4_test_locked_slot(const struct nfs4_slot_table *tbl,
		u32 slotid)
{
	return !!test_bit(slotid, tbl->used_slots);
}

#if defined(CONFIG_NFS_V4_1)
extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl,
		u32 target_highest_slotid);
extern void nfs41_update_target_slotid(struct nfs4_slot_table *tbl,
		struct nfs4_slot *slot,
		struct nfs4_sequence_res *res);

extern int nfs4_setup_session_slot_tables(struct nfs4_session *ses);

extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
extern void nfs4_destroy_session(struct nfs4_session *session);
extern int nfs4_init_session(struct nfs_client *clp);
extern int nfs4_init_ds_session(struct nfs_client *, unsigned long);

/*
 * Determine if sessions are in use.
 */
static inline int nfs4_has_session(const struct nfs_client *clp)
{
	if (clp->cl_session)
		return 1;
	return 0;
}

static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
{
	if (nfs4_has_session(clp))
		return (clp->cl_session->flags & SESSION4_PERSIST);
	return 0;
}

static inline void nfs4_copy_sessionid(struct nfs4_sessionid *dst,
		const struct nfs4_sessionid *src)
{
	memcpy(dst->data, src->data, NFS4_MAX_SESSIONID_LEN);
}

#ifdef CONFIG_CRC32
/*
 * nfs_session_id_hash - calculate the crc32 hash for the session id
 * @session - pointer to session
 */
#define nfs_session_id_hash(sess_id) \
	(~crc32_le(0xFFFFFFFF, &(sess_id)->data[0], sizeof((sess_id)->data)))
#else
#define nfs_session_id_hash(session) (0)
#endif
#else /* defined(CONFIG_NFS_V4_1) */

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

/*
 * Determine if sessions are in use.
 */
static inline int nfs4_has_session(const struct nfs_client *clp)
{
	return 0;
}

static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
{
	return 0;
}

#endif /* defined(CONFIG_NFS_V4_1) */
#endif /* IS_ENABLED(CONFIG_NFS_V4) */
#endif /* __LINUX_FS_NFS_NFS4SESSION_H */