[SNDVOL32] Advanced controls dialog: Remove the TBS_AUTOTICKS style from the trackbar...
[reactos.git] / base / services / nfsd / nfs41_session.c
1 /* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
3 *
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
6 *
7 * This library is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * without any warranty; without even the implied warranty of merchantability
14 * or fitness for a particular purpose. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 */
21
22 #include <windows.h>
23 #include <process.h>
24 #include <stdio.h>
25
26 #include "nfs41_ops.h"
27 #include "nfs41_callback.h"
28 #include "util.h"
29 #include "daemon_debug.h"
30
31
32 /* after a CB_RECALL_SLOT or NFS4ERR_BADSLOT, wait a short time for the
33 * SEQUENCE.target_highest_slotid to catch up before updating max_slots again */
34 #define MAX_SLOTS_DELAY 2000 /* in milliseconds */
35
36
37 /* predicate for nfs41_slot_table.cond */
38 static int slot_table_avail(
39 IN const nfs41_slot_table *table)
40 {
41 return table->num_used < table->max_slots;
42 }
43
44 /* session slot mechanism */
45 static void init_slot_table(nfs41_slot_table *table)
46 {
47 uint32_t i;
48 EnterCriticalSection(&table->lock);
49 table->max_slots = NFS41_MAX_NUM_SLOTS;
50 for (i = 0; i < NFS41_MAX_NUM_SLOTS; i++) {
51 table->seq_nums[i] = 1;
52 table->used_slots[i] = 0;
53 }
54 table->highest_used = table->num_used = 0;
55 table->target_delay = 0;
56
57 /* wake any threads waiting on a slot */
58 if (slot_table_avail(table))
59 WakeAllConditionVariable(&table->cond);
60 LeaveCriticalSection(&table->lock);
61 }
62
63 static void resize_slot_table(
64 IN nfs41_slot_table *table,
65 IN uint32_t target_highest_slotid)
66 {
67 if (target_highest_slotid >= NFS41_MAX_NUM_SLOTS)
68 target_highest_slotid = NFS41_MAX_NUM_SLOTS - 1;
69
70 if (table->max_slots != target_highest_slotid + 1) {
71 dprintf(2, "updated max_slots %u to %u\n",
72 table->max_slots, target_highest_slotid + 1);
73 table->max_slots = target_highest_slotid + 1;
74
75 if (slot_table_avail(table))
76 WakeAllConditionVariable(&table->cond);
77 }
78 }
79
80 void nfs41_session_bump_seq(
81 IN nfs41_session *session,
82 IN uint32_t slotid,
83 IN uint32_t target_highest_slotid)
84 {
85 nfs41_slot_table *table = &session->table;
86
87 AcquireSRWLockShared(&session->client->session_lock);
88 EnterCriticalSection(&table->lock);
89
90 if (slotid < NFS41_MAX_NUM_SLOTS)
91 table->seq_nums[slotid]++;
92
93 /* adjust max_slots in response to changes in target_highest_slotid,
94 * but not immediately after a CB_RECALL_SLOT or NFS4ERR_BADSLOT error */
95 if (table->target_delay <= GetTickCount64())
96 resize_slot_table(table, target_highest_slotid);
97
98 LeaveCriticalSection(&table->lock);
99 ReleaseSRWLockShared(&session->client->session_lock);
100 }
101
102 void nfs41_session_free_slot(
103 IN nfs41_session *session,
104 IN uint32_t slotid)
105 {
106 nfs41_slot_table *table = &session->table;
107
108 AcquireSRWLockShared(&session->client->session_lock);
109 EnterCriticalSection(&table->lock);
110
111 /* flag the slot as unused */
112 if (slotid < NFS41_MAX_NUM_SLOTS && table->used_slots[slotid]) {
113 table->used_slots[slotid] = 0;
114 table->num_used--;
115 }
116 /* update highest_used if necessary */
117 if (slotid == table->highest_used) {
118 while (table->highest_used && !table->used_slots[table->highest_used])
119 table->highest_used--;
120 }
121 dprintf(3, "freeing slot#=%d used=%d highest=%d\n",
122 slotid, table->num_used, table->highest_used);
123
124 /* wake any threads waiting on a slot */
125 if (slot_table_avail(table))
126 WakeAllConditionVariable(&table->cond);
127
128 LeaveCriticalSection(&table->lock);
129 ReleaseSRWLockShared(&session->client->session_lock);
130 }
131
132 void nfs41_session_get_slot(
133 IN nfs41_session *session,
134 OUT uint32_t *slot,
135 OUT uint32_t *seqid,
136 OUT uint32_t *highest)
137 {
138 nfs41_slot_table *table = &session->table;
139 uint32_t i;
140
141 AcquireSRWLockShared(&session->client->session_lock);
142 EnterCriticalSection(&table->lock);
143
144 /* wait for an available slot */
145 while (!slot_table_avail(table))
146 SleepConditionVariableCS(&table->cond, &table->lock, INFINITE);
147
148 for (i = 0; i < table->max_slots; i++) {
149 if (table->used_slots[i])
150 continue;
151
152 table->used_slots[i] = 1;
153 table->num_used++;
154 if (i > table->highest_used)
155 table->highest_used = i;
156
157 *slot = i;
158 *seqid = table->seq_nums[i];
159 *highest = table->highest_used;
160 break;
161 }
162 LeaveCriticalSection(&table->lock);
163 ReleaseSRWLockShared(&session->client->session_lock);
164
165 dprintf(2, "session %p: using slot#=%d with seq#=%d highest=%d\n",
166 session, *slot, *seqid, *highest);
167 }
168
169 int nfs41_session_recall_slot(
170 IN nfs41_session *session,
171 IN OUT uint32_t target_highest_slotid)
172 {
173 nfs41_slot_table *table = &session->table;
174
175 AcquireSRWLockShared(&session->client->session_lock);
176 EnterCriticalSection(&table->lock);
177 resize_slot_table(table, target_highest_slotid);
178 table->target_delay = GetTickCount64() + MAX_SLOTS_DELAY;
179 LeaveCriticalSection(&table->lock);
180 ReleaseSRWLockShared(&session->client->session_lock);
181
182 return NFS4_OK;
183 }
184
185 int nfs41_session_bad_slot(
186 IN nfs41_session *session,
187 IN OUT nfs41_sequence_args *args)
188 {
189 nfs41_slot_table *table = &session->table;
190 int status = NFS4ERR_BADSLOT;
191
192 if (args->sa_slotid == 0) {
193 eprintf("server bug detected: NFS4ERR_BADSLOT for slotid=0\n");
194 goto out;
195 }
196
197 /* avoid using any slots >= bad_slotid */
198 EnterCriticalSection(&table->lock);
199 if (table->max_slots > args->sa_slotid) {
200 resize_slot_table(table, args->sa_slotid);
201 table->target_delay = GetTickCount64() + MAX_SLOTS_DELAY;
202 }
203 LeaveCriticalSection(&table->lock);
204
205 /* get a new slot */
206 nfs41_session_free_slot(session, args->sa_slotid);
207 nfs41_session_get_slot(session, &args->sa_slotid,
208 &args->sa_sequenceid, &args->sa_highest_slotid);
209 status = NFS4_OK;
210 out:
211 return status;
212 }
213
214 void nfs41_session_sequence(
215 nfs41_sequence_args *args,
216 nfs41_session *session,
217 bool_t cachethis)
218 {
219 nfs41_session_get_slot(session, &args->sa_slotid,
220 &args->sa_sequenceid, &args->sa_highest_slotid);
221 args->sa_sessionid = session->session_id;
222 args->sa_cachethis = cachethis;
223 }
224
225
226 /* session renewal */
227 static unsigned int WINAPI renew_session(void *args)
228 {
229 int status = NO_ERROR;
230 nfs41_session *session = (nfs41_session *)args;
231 /* sleep for 2/3 of lease_time */
232 const uint32_t sleep_time = (2 * session->lease_time*1000)/3;
233
234 dprintf(1, "Creating renew_session thread: %p\n", session->renew_thread);
235 while(1) {
236 dprintf(1, "Going to sleep for %dmsecs\n", sleep_time);
237 Sleep(sleep_time);
238 status = nfs41_send_sequence(session);
239 if (status)
240 dprintf(1, "renewal thread: nfs41_send_sequence failed %d\n", status);
241 }
242 return status;
243 }
244
245 /* session creation */
246 static int session_alloc(
247 IN nfs41_client *client,
248 OUT nfs41_session **session_out)
249 {
250 nfs41_session *session;
251 int status = NO_ERROR;
252
253 session = calloc(1, sizeof(nfs41_session));
254 if (session == NULL) {
255 status = GetLastError();
256 goto out;
257 }
258 session->client = client;
259 session->renew_thread = INVALID_HANDLE_VALUE;
260 session->isValidState = FALSE;
261
262 InitializeCriticalSection(&session->table.lock);
263 InitializeConditionVariable(&session->table.cond);
264
265 init_slot_table(&session->table);
266
267 //initialize session lock
268 InitializeSRWLock(&client->session_lock);
269
270 /* initialize the back channel */
271 nfs41_callback_session_init(session);
272
273 *session_out = session;
274 out:
275 return status;
276 }
277
278 int nfs41_session_create(
279 IN nfs41_client *client,
280 IN nfs41_session **session_out)
281 {
282 nfs41_session *session;
283 int status;
284
285 status = session_alloc(client, &session);
286 if (status) {
287 eprintf("session_alloc() failed with %d\n", status);
288 goto out;
289 }
290
291 AcquireSRWLockShared(&client->exid_lock);
292 if (client->rpc->needcb)
293 session->flags |= CREATE_SESSION4_FLAG_CONN_BACK_CHAN;
294 session->flags |= CREATE_SESSION4_FLAG_PERSIST;
295 ReleaseSRWLockShared(&client->exid_lock);
296
297 status = nfs41_create_session(client, session, TRUE);
298 if (status) {
299 eprintf("nfs41_create_session failed %d\n", status);
300 status = ERROR_BAD_NET_RESP;
301 goto out_err;
302 }
303
304 AcquireSRWLockExclusive(&session->client->session_lock);
305 client->session = session;
306 session->isValidState = TRUE;
307 ReleaseSRWLockExclusive(&session->client->session_lock);
308 *session_out = session;
309 out:
310 return status;
311
312 out_err:
313 nfs41_session_free(session);
314 goto out;
315 }
316
317 /* session renewal */
318 int nfs41_session_renew(
319 IN nfs41_session *session)
320 {
321 int status;
322
323 AcquireSRWLockExclusive(&session->client->session_lock);
324 session->cb_session.cb_seqnum = 0;
325 init_slot_table(&session->table);
326
327 status = nfs41_create_session(session->client, session, FALSE);
328 ReleaseSRWLockExclusive(&session->client->session_lock);
329 return status;
330 }
331
332 int nfs41_session_set_lease(
333 IN nfs41_session *session,
334 IN uint32_t lease_time)
335 {
336 int status = NO_ERROR;
337 uint32_t thread_id;
338
339 if (valid_handle(session->renew_thread)) {
340 eprintf("nfs41_session_set_lease(): session "
341 "renewal thread already started!\n");
342 goto out;
343 }
344
345 if (lease_time == 0) {
346 eprintf("nfs41_session_set_lease(): invalid lease_time=0\n");
347 status = ERROR_INVALID_PARAMETER;
348 goto out;
349 }
350
351 session->lease_time = lease_time;
352 session->renew_thread = (HANDLE)_beginthreadex(NULL,
353 0, renew_session, session, 0, &thread_id);
354 if (!valid_handle(session->renew_thread)) {
355 status = GetLastError();
356 eprintf("_beginthreadex failed %d\n", status);
357 goto out;
358 }
359 out:
360 return status;
361 }
362
363 void nfs41_session_free(
364 IN nfs41_session *session)
365 {
366 AcquireSRWLockExclusive(&session->client->session_lock);
367 if (valid_handle(session->renew_thread)) {
368 dprintf(1, "nfs41_session_free: terminating session renewal thread\n");
369 if (!TerminateThread(session->renew_thread, NO_ERROR))
370 eprintf("failed to terminate renewal thread %p\n",
371 session->renew_thread);
372 }
373
374 if (session->isValidState) {
375 session->client->rpc->is_valid_session = FALSE;
376 nfs41_destroy_session(session);
377 }
378 DeleteCriticalSection(&session->table.lock);
379 ReleaseSRWLockExclusive(&session->client->session_lock);
380 free(session);
381 }