ReactOS  0.4.14-dev-115-g4576127
recovery.c
Go to the documentation of this file.
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 <time.h>
23 
24 #include "recovery.h"
25 #include "delegation.h"
26 #include "nfs41_callback.h"
27 #include "nfs41_compound.h"
28 #include "nfs41_ops.h"
29 #include "daemon_debug.h"
30 
31 
32 /* session/client recovery uses a lock and condition variable in nfs41_client
33  * to prevent multiple threads from attempting to recover at the same time */
36 {
37  bool_t status = TRUE;
38 
39  EnterCriticalSection(&client->recovery.lock);
40 
41  if (!client->recovery.in_recovery) {
42  dprintf(1, "Entering recovery mode for client %llu\n", client->clnt_id);
43  client->recovery.in_recovery = TRUE;
44  } else {
45  status = FALSE;
46  dprintf(1, "Waiting for recovery of client %llu\n", client->clnt_id);
47  while (client->recovery.in_recovery)
48  SleepConditionVariableCS(&client->recovery.cond,
49  &client->recovery.lock, INFINITE);
50  dprintf(1, "Woke up after recovery of client %llu\n", client->clnt_id);
51  }
52 
53  LeaveCriticalSection(&client->recovery.lock);
54  return status;
55 }
56 
59 {
60  EnterCriticalSection(&client->recovery.lock);
61  dprintf(1, "Finished recovery for client %llu\n", client->clnt_id);
62  client->recovery.in_recovery = FALSE;
63  WakeAllConditionVariable(&client->recovery.cond);
64  LeaveCriticalSection(&client->recovery.lock);
65 }
66 
67 
68 /* session/client/state recovery */
70  IN nfs41_session *session,
71  IN bool_t client_state_lost)
72 {
73  enum nfsstat4 status = NFS4_OK;
74 
75 restart_recovery:
76  /* recover the session */
77  status = nfs41_session_renew(session);
78 
80  /* recover the client */
81  client_state_lost = TRUE;
82  status = nfs41_client_renew(session->client);
83  if (status == NFS4_OK)
84  goto restart_recovery; /* resume session recovery */
85 
86  eprintf("nfs41_client_renew() failed with %d\n", status);
87  } else if (status) {
88  eprintf("nfs41_session_renew() failed with %d\n", status);
89  } else if (client_state_lost) {
90  /* recover the client's state */
91  status = nfs41_recover_client_state(session, session->client);
93  goto restart_recovery;
94  }
95  return status;
96 }
97 
99  IN nfs41_session *session,
100  IN uint32_t flags)
101 {
102  const uint32_t revoked = flags &
107  const uint32_t restarted = flags &
109 
110  /* no state recovery needed */
111  if (revoked == 0 && restarted == 0)
112  return;
113 
114  if (!nfs41_recovery_start_or_wait(session->client))
115  return;
116 
117  if (revoked) {
118  /* free stateids and attempt to recover them */
119  nfs41_client_state_revoked(session, session->client, revoked);
120 
121  /* if RESTART_RECLAIM_NEEDED is also set, just do RECLAIM_COMPLETE */
122  if (restarted) nfs41_reclaim_complete(session);
123 
124  } else if (restarted) {
125  /* do server reboot state recovery */
126  uint32_t status = nfs41_recover_client_state(session, session->client);
127  if (status == NFS4ERR_BADSESSION) {
128  /* recover the session and finish state recovery */
129  nfs41_recover_session(session, TRUE);
130  }
131  }
132 
133  nfs41_recovery_finish(session->client);
134 }
135 
136 
137 /* client state recovery for server reboot or lease expiration */
139  IN nfs41_session *session,
142  IN state_owner4 *owner,
144  IN uint32_t deny,
145  OUT stateid4 *stateid,
146  OUT open_delegation4 *delegation)
147 {
148  /* reclaim the open stateid with CLAIM_PREVIOUS */
149  open_claim4 claim;
150  claim.claim = CLAIM_PREVIOUS;
151  claim.u.prev.delegate_type = delegation->type;
152 
153  return nfs41_open(session, parent, file, owner, &claim, access, deny,
154  OPEN4_NOCREATE, 0, NULL, FALSE, stateid, delegation, NULL);
155 }
156 
158  IN nfs41_session *session,
161  IN state_owner4 *owner,
163  IN uint32_t deny,
164  OUT stateid4 *stateid,
165  OUT open_delegation4 *delegation)
166 {
167  open_claim4 claim;
168  int status;
169 
170  if (delegation->type != OPEN_DELEGATE_NONE) {
171  /* attempt out-of-grace recovery with CLAIM_DELEGATE_PREV */
172  claim.claim = CLAIM_DELEGATE_PREV;
173  claim.u.deleg_prev.filename = &file->name;
174 
175  status = nfs41_open(session, parent, file, owner,
176  &claim, access, deny, OPEN4_NOCREATE, 0, NULL, FALSE,
177  stateid, delegation, NULL);
179  goto out;
180 
181  /* server support for CLAIM_DELEGATE_PREV is optional;
182  * fall back to CLAIM_NULL on errors */
183  }
184 
185  /* attempt out-of-grace recovery with CLAIM_NULL */
186  claim.claim = CLAIM_NULL;
187  claim.u.null.filename = &file->name;
188 
189  /* ask nicely for the delegation we had */
190  if (delegation->type == OPEN_DELEGATE_READ)
192  else if (delegation->type == OPEN_DELEGATE_WRITE)
194 
195  status = nfs41_open(session, parent, file, owner,
196  &claim, access, deny, OPEN4_NOCREATE, 0, NULL, FALSE,
197  stateid, delegation, NULL);
198 out:
199  return status;
200 }
201 
202 static int recover_open(
203  IN nfs41_session *session,
205  IN OUT bool_t *grace)
206 {
207  open_delegation4 delegation = { 0 };
208  stateid4 stateid = { 0 };
210 
211  /* check for an associated delegation */
213  if (open->delegation.state) {
214  nfs41_delegation_state *deleg = open->delegation.state;
215  if (deleg->revoked) {
216  /* reclaim the delegation along with the open */
217  AcquireSRWLockShared(&deleg->lock);
218  delegation.type = deleg->state.type;
219  ReleaseSRWLockShared(&deleg->lock);
220  } else if (deleg->state.recalled) {
221  /* we'll need an open stateid regardless */
222  } else if (list_empty(&open->locks.list)) {
223  /* if there are locks, we need an open stateid to
224  * reclaim them; otherwise, the open can be delegated */
225  open->do_close = FALSE;
226  status = NFS4_OK;
227  }
228  }
230 
231  if (status == NFS4_OK) /* use existing delegation */
232  goto out;
233 
234  if (*grace) {
235  status = recover_open_grace(session, &open->parent, &open->file,
236  &open->owner, open->share_access, open->share_deny,
237  &stateid, &delegation);
238  if (status == NFS4ERR_NO_GRACE) {
239  *grace = FALSE;
240  /* send RECLAIM_COMPLETE before any out-of-grace recovery */
241  nfs41_reclaim_complete(session);
242  }
243  }
244  if (!*grace) {
245  status = recover_open_no_grace(session, &open->parent, &open->file,
246  &open->owner, open->share_access, open->share_deny,
247  &stateid, &delegation);
248  }
249 
250  if (status)
251  goto out;
252 
254  /* update the open stateid */
255  memcpy(&open->stateid, &stateid, sizeof(stateid4));
256  open->do_close = TRUE;
257 
258  if (open->delegation.state) {
259  nfs41_delegation_state *deleg = open->delegation.state;
260  if (deleg->revoked) {
261  /* update delegation state */
262  AcquireSRWLockExclusive(&deleg->lock);
263  if (delegation.type != OPEN_DELEGATE_READ &&
264  delegation.type != OPEN_DELEGATE_WRITE) {
265  eprintf("recover_open() got delegation type %u, "
266  "expected %u\n", delegation.type, deleg->state.type);
267  } else {
268  memcpy(&deleg->state, &delegation, sizeof(open_delegation4));
269  deleg->revoked = FALSE;
270  }
271  ReleaseSRWLockExclusive(&deleg->lock);
272  }
273  } else /* granted a new delegation? */
274  nfs41_delegation_granted(session, &open->parent, &open->file,
275  &delegation, FALSE, &open->delegation.state);
277 out:
278  return status;
279 }
280 
281 static int recover_locks(
282  IN nfs41_session *session,
284  IN OUT bool_t *grace)
285 {
286  stateid_arg stateid;
287  struct list_entry *entry;
289  int status = NFS4_OK;
290 
292 
293  /* initialize the open stateid for the first lock request */
294  memcpy(&stateid.stateid, &open->stateid, sizeof(stateid4));
295  stateid.type = STATEID_OPEN;
296  stateid.open = open;
297  stateid.delegation = NULL;
298 
299  /* recover any locks for this open */
300  list_for_each(entry, &open->locks.list) {
302  if (lock->delegated)
303  continue;
304 
305  if (*grace) {
306  status = nfs41_lock(session, &open->file, &open->owner,
307  lock->exclusive ? WRITE_LT : READ_LT, lock->offset,
308  lock->length, TRUE, FALSE, &stateid);
309  if (status == NFS4ERR_NO_GRACE) {
310  *grace = FALSE;
311  /* send RECLAIM_COMPLETE before any out-of-grace recovery */
312  nfs41_reclaim_complete(session);
313  }
314  }
315  if (!*grace) {
316  /* attempt out-of-grace recovery with a normal LOCK */
317  status = nfs41_lock(session, &open->file, &open->owner,
318  lock->exclusive ? WRITE_LT : READ_LT, lock->offset,
319  lock->length, FALSE, FALSE, &stateid);
320  }
321  if (status == NFS4ERR_BADSESSION)
322  break;
323  }
324 
325  if (status != NFS4ERR_BADSESSION) {
326  /* if we got a lock stateid back, save the lock with the open */
327  if (stateid.type == STATEID_LOCK)
328  memcpy(&open->locks.stateid, &stateid.stateid, sizeof(stateid4));
329  else
330  open->locks.stateid.seqid = 0;
331  }
332 
334  return status;
335 }
336 
337 /* delegation recovery via WANT_DELEGATION */
339  IN nfs41_session *session,
340  IN nfs41_delegation_state *deleg,
341  IN OUT bool_t *grace)
342 {
343  deleg_claim4 claim;
344  open_delegation4 delegation = { 0 };
345  uint32_t want_flags = 0;
346  int status = NFS4_OK;
347 
348  AcquireSRWLockShared(&deleg->lock);
349  delegation.type = deleg->state.type;
350  ReleaseSRWLockShared(&deleg->lock);
351 
352  if (delegation.type == OPEN_DELEGATE_READ)
354  else
356 
357  if (*grace) {
358  /* recover the delegation with WANT_DELEGATION/CLAIM_PREVIOUS */
359  claim.claim = CLAIM_PREVIOUS;
360  claim.prev_delegate_type = delegation.type;
361 
362  status = nfs41_want_delegation(session, &deleg->file, &claim,
363  want_flags, FALSE, &delegation);
364  if (status == NFS4ERR_NO_GRACE) {
365  *grace = FALSE;
366  /* send RECLAIM_COMPLETE before any out-of-grace recovery */
367  nfs41_reclaim_complete(session);
368  }
369  }
370  if (!*grace) {
371  /* attempt out-of-grace recovery with with CLAIM_DELEG_PREV_FH */
372  claim.claim = CLAIM_DELEG_PREV_FH;
373 
374  status = nfs41_want_delegation(session, &deleg->file, &claim,
375  want_flags, FALSE, &delegation);
376  }
377  if (status)
378  goto out;
379 
380  /* update delegation state */
381  AcquireSRWLockExclusive(&deleg->lock);
382  if (delegation.type != OPEN_DELEGATE_READ &&
383  delegation.type != OPEN_DELEGATE_WRITE) {
384  eprintf("recover_delegation_want() got delegation type %u, "
385  "expected %u\n", delegation.type, deleg->state.type);
386  } else {
387  memcpy(&deleg->state, &delegation, sizeof(open_delegation4));
388  deleg->revoked = FALSE;
389  }
390  ReleaseSRWLockExclusive(&deleg->lock);
391 out:
392  return status;
393 }
394 
395 /* delegation recovery via OPEN (requires corresponding CLOSE) */
397  IN nfs41_session *session,
398  IN nfs41_delegation_state *deleg,
399  IN OUT bool_t *grace)
400 {
401  state_owner4 owner;
402  open_delegation4 delegation = { 0 };
403  stateid_arg stateid;
406  int status = NFS4_OK;
407 
408  /* choose the desired access mode based on delegation type */
409  AcquireSRWLockShared(&deleg->lock);
410  delegation.type = deleg->state.type;
411  if (delegation.type == OPEN_DELEGATE_WRITE)
413  else
415  ReleaseSRWLockShared(&deleg->lock);
416 
417  /* construct a temporary open owner by concatenating the time
418  * in seconds with the delegation pointer */
419  time((time_t*)owner.owner);
420  memcpy(owner.owner + sizeof(time_t), deleg, sizeof(deleg));
421  owner.owner_len = sizeof(time_t) + sizeof(deleg);
422 
423  if (*grace) {
424  status = recover_open_grace(session, &deleg->parent, &deleg->file,
425  &owner, access, deny, &stateid.stateid, &delegation);
426  if (status == NFS4ERR_NO_GRACE) {
427  *grace = FALSE;
428  /* send RECLAIM_COMPLETE before any out-of-grace recovery */
429  nfs41_reclaim_complete(session);
430  }
431  }
432  if (!*grace) {
433  status = recover_open_no_grace(session, &deleg->parent, &deleg->file,
434  &owner, access, deny, &stateid.stateid, &delegation);
435  }
436  if (status)
437  goto out;
438 
439  /* update delegation state */
440  AcquireSRWLockExclusive(&deleg->lock);
441  if (delegation.type != OPEN_DELEGATE_READ &&
442  delegation.type != OPEN_DELEGATE_WRITE) {
443  eprintf("recover_delegation_open() got delegation type %u, "
444  "expected %u\n", delegation.type, deleg->state.type);
445  } else {
446  memcpy(&deleg->state, &delegation, sizeof(open_delegation4));
447  deleg->revoked = FALSE;
448  }
449  ReleaseSRWLockExclusive(&deleg->lock);
450 
451  /* send CLOSE to free the open stateid */
452  stateid.open = NULL;
453  stateid.delegation = NULL;
454  stateid.type = STATEID_OPEN;
455  nfs41_close(session, &deleg->file, &stateid);
456 out:
457  return status;
458 }
459 
461  IN nfs41_session *session,
462  IN nfs41_delegation_state *deleg,
463  IN OUT bool_t *grace,
464  IN OUT bool_t *want_supported)
465 {
466  int status;
467 
468  /* 10.2.1. Delegation Recovery
469  * When a client needs to reclaim a delegation and there is no
470  * associated open, the client may use the CLAIM_PREVIOUS variant
471  * of the WANT_DELEGATION operation. However, since the server is
472  * not required to support this operation, an alternative is to
473  * reclaim via a dummy OPEN together with the delegation using an
474  * OPEN of type CLAIM_PREVIOUS. */
475  if (*want_supported)
476  status = recover_delegation_want(session, deleg, grace);
477  else
479 
480  if (status == NFS4ERR_NOTSUPP) {
481  *want_supported = FALSE;
482  status = recover_delegation_open(session, deleg, grace);
483  }
484  return status;
485 }
486 
488  IN nfs41_session *session,
490 {
493  struct client_state *state = &session->client->state;
494  struct list_entry *entry;
496  nfs41_delegation_state *deleg;
497  bool_t grace = TRUE;
498  bool_t want_supported = TRUE;
499  int status = NFS4_OK;
500 
501  EnterCriticalSection(&state->lock);
502 
503  /* flag all delegations as revoked until successful recovery;
504  * recover_open() and recover_delegation_open() will only ask
505  * for delegations when revoked = TRUE */
506  list_for_each(entry, &state->delegations) {
508  deleg->revoked = TRUE;
509  }
510 
511  /* recover each of the client's opens and associated delegations */
512  list_for_each(entry, &state->opens) {
514  status = recover_open(session, open, &grace);
515  if (status == NFS4_OK)
516  status = recover_locks(session, open, &grace);
517  if (status == NFS4ERR_BADSESSION)
518  goto unlock;
519  }
520 
521  /* recover delegations that weren't associated with any opens */
522  list_for_each(entry, &state->delegations) {
524  if (deleg->revoked) {
525  status = recover_delegation(session,
526  deleg, &grace, &want_supported);
527  if (status == NFS4ERR_BADSESSION)
528  goto unlock;
529  }
530  }
531 
532  /* return any delegations that were reclaimed as 'recalled' */
534 unlock:
535  LeaveCriticalSection(&state->lock);
536 
537  /* revoke all of the client's layouts */
539 
540  if (grace && status != NFS4ERR_BADSESSION) {
541  /* send reclaim_complete, but don't fail on errors */
542  nfs41_reclaim_complete(session);
543  }
544  return status;
545 }
546 
548  IN struct list_entry *delegations,
549  IN struct list_entry *opens,
550  OUT stateid_arg **stateids_out,
551  OUT uint32_t **statuses_out)
552 {
553  struct list_entry *entry;
555  nfs41_delegation_state *deleg;
556  stateid_arg *stateids = NULL;
557  uint32_t *statuses = NULL;
558  uint32_t i = 0, count = 0;
559 
560  /* count how many stateids the client needs to test */
561  list_for_each(entry, delegations)
562  count++;
563  list_for_each(entry, opens)
564  count += 3; /* open and potentially lock and layout */
565 
566  if (count == 0)
567  goto out;
568 
569  /* allocate the stateid and status arrays */
570  stateids = calloc(count, sizeof(stateid_arg));
571  if (stateids == NULL)
572  goto out_err;
573  statuses = calloc(count, sizeof(uint32_t));
574  if (statuses == NULL)
575  goto out_err;
576  memset(statuses, NFS4ERR_BAD_STATEID, count * sizeof(uint32_t));
577 
578  /* copy stateids into the array */
579  list_for_each(entry, delegations) {
581  AcquireSRWLockShared(&deleg->lock);
582  /* delegation stateid */
583  memcpy(&stateids[i].stateid, &deleg->state.stateid, sizeof(stateid4));
584  stateids[i].type = STATEID_DELEG_FILE;
585  stateids[i].delegation = deleg;
586  i++;
587  ReleaseSRWLockShared(&deleg->lock);
588  }
589 
590  list_for_each(entry, opens) {
592 
593  AcquireSRWLockShared(&open->lock);
594  /* open stateid */
595  memcpy(&stateids[i].stateid, &open->stateid, sizeof(stateid4));
596  stateids[i].type = STATEID_OPEN;
597  stateids[i].open = open;
598  i++;
599 
600  if (open->locks.stateid.seqid) { /* lock stateid? */
601  memcpy(&stateids[i].stateid, &open->locks.stateid, sizeof(stateid4));
602  stateids[i].type = STATEID_LOCK;
603  stateids[i].open = open;
604  i++;
605  }
606 
607  if (open->layout) { /* layout stateid? */
608  AcquireSRWLockShared(&open->layout->lock);
609  if (open->layout->stateid.seqid) {
610  memcpy(&stateids[i].stateid, &open->layout->stateid, sizeof(stateid4));
611  stateids[i].type = STATEID_LAYOUT;
612  stateids[i].open = open;
613  i++;
614  }
615  ReleaseSRWLockShared(&open->layout->lock);
616  }
617  ReleaseSRWLockShared(&open->lock);
618  }
619 
620  count = i;
621  *stateids_out = stateids;
622  *statuses_out = statuses;
623 out:
624  return count;
625 
626 out_err:
627  free(stateids);
628  free(statuses);
629  count = 0;
630  goto out;
631 }
632 
634  IN nfs41_session *session,
636  IN uint32_t revoked)
637 {
640  struct list_entry empty, *opens;
641  struct client_state *clientstate = &session->client->state;
642  stateid_arg *stateids = NULL;
643  uint32_t *statuses = NULL;
644  uint32_t i, count;
645  bool_t grace = TRUE;
646  bool_t want_supported = TRUE;
647 
648  EnterCriticalSection(&clientstate->lock);
649 
650  if (revoked == SEQ4_STATUS_RECALLABLE_STATE_REVOKED) {
651  /* only delegations were revoked. use an empty list for opens */
652  list_init(&empty);
653  opens = &empty;
654  } else {
655  opens = &clientstate->opens;
656  }
657 
658  /* get an array of the client's stateids */
659  count = stateid_array(&clientstate->delegations,
660  opens, &stateids, &statuses);
661  if (count == 0)
662  goto out;
663 
664  /* determine which stateids were revoked with TEST_STATEID */
665  if ((revoked & SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED) == 0)
666  nfs41_test_stateid(session, stateids, count, statuses);
667 
668  /* free all revoked stateids with FREE_STATEID */
669  for (i = 0; i < count; i++)
670  if (statuses[i])
671  nfs41_free_stateid(session, &stateids[i].stateid);
672 
673  /* revoke all of the client's layouts */
675 
676  /* recover the revoked stateids */
677  for (i = 0; i < count; i++) {
678  if (statuses[i]) {
679  if (stateids[i].type == STATEID_DELEG_FILE)
680  stateids[i].delegation->revoked = TRUE;
681  else if (stateids[i].type == STATEID_OPEN)
682  recover_open(session, stateids[i].open, &grace);
683  else if (stateids[i].type == STATEID_LOCK)
684  recover_locks(session, stateids[i].open, &grace);
685  }
686  }
687  for (i = 0; i < count; i++) {
688  /* delegations that weren't recovered by recover_open() */
689  if (statuses[i] && stateids[i].type == STATEID_DELEG_FILE
690  && stateids[i].delegation->revoked)
691  recover_delegation(session, stateids[i].delegation,
692  &grace, &want_supported);
693  }
694 
696 out:
697  LeaveCriticalSection(&clientstate->lock);
698  free(stateids);
699  free(statuses);
700 }
701 
702 
704  IN nfs_argop4 *argop,
705  IN stateid_arg *stateid)
706 {
707  bool_t retry = FALSE;
708 
709  if (stateid->open) {
710  stateid4 *source = &stateid->open->stateid;
711 
712  /* if the source stateid is different, update and retry */
713  AcquireSRWLockShared(&stateid->open->lock);
714  if (memcmp(&stateid->stateid, source, sizeof(stateid4))) {
715  memcpy(&stateid->stateid, source, sizeof(stateid4));
716  retry = TRUE;
717  }
718  ReleaseSRWLockShared(&stateid->open->lock);
719  }
720  return retry;
721 }
722 
724  IN nfs_argop4 *argop,
725  IN stateid_arg *stateid)
726 {
727  bool_t retry = FALSE;
728 
729  if (stateid->open) {
730  stateid4 *source = &stateid->open->locks.stateid;
731 
732  /* if the source stateid is different, update and retry */
733  AcquireSRWLockShared(&stateid->open->lock);
734  if (memcmp(&stateid->stateid, source, sizeof(stateid4))) {
735  if (argop->op == OP_LOCK && source->seqid == 0) {
736  /* resend LOCK with an open stateid */
737  nfs41_lock_args *lock = (nfs41_lock_args*)argop->arg;
738  lock->locker.new_lock_owner = 1;
739  lock->locker.u.open_owner.open_stateid = stateid;
740  lock->locker.u.open_owner.lock_owner = &stateid->open->owner;
741  source = &stateid->open->stateid;
742  }
743 
744  memcpy(&stateid->stateid, source, sizeof(stateid4));
745  retry = TRUE;
746  }
747  ReleaseSRWLockShared(&stateid->open->lock);
748  }
749  return retry;
750 }
751 
753  IN nfs_argop4 *argop,
754  IN stateid_arg *stateid)
755 {
756  bool_t retry = FALSE;
757 
758  if (stateid->open) {
759  /* if the source stateid is different, update and retry */
760  AcquireSRWLockShared(&stateid->open->lock);
761  if (argop->op == OP_OPEN && stateid->open->do_close) {
762  /* for nfs41_delegation_to_open(); if we've already reclaimed
763  * an open stateid, just fail this OPEN with BAD_STATEID */
764  } else if (stateid->open->delegation.state) {
765  nfs41_delegation_state *deleg = stateid->open->delegation.state;
766  stateid4 *source = &deleg->state.stateid;
767  AcquireSRWLockShared(&deleg->lock);
768  if (memcmp(&stateid->stateid, source, sizeof(stateid4))) {
769  memcpy(&stateid->stateid, source, sizeof(stateid4));
770  retry = TRUE;
771  }
772  ReleaseSRWLockShared(&deleg->lock);
773  }
774  ReleaseSRWLockShared(&stateid->open->lock);
775  } else if (stateid->delegation) {
776  nfs41_delegation_state *deleg = stateid->delegation;
777  stateid4 *source = &deleg->state.stateid;
778  AcquireSRWLockShared(&deleg->lock);
779  if (memcmp(&stateid->stateid, source, sizeof(stateid4))) {
780  memcpy(&stateid->stateid, source, sizeof(stateid4));
781  retry = TRUE;
782  }
783  ReleaseSRWLockShared(&deleg->lock);
784  }
785  return retry;
786 }
787 
789  IN nfs41_session *session,
790  IN nfs_argop4 *argop)
791 {
792  stateid_arg *stateid = NULL;
793 
794  /* get the stateid_arg from the operation's arguments */
795  if (argop->op == OP_OPEN) {
797  if (open->claim->claim == CLAIM_DELEGATE_CUR)
798  stateid = open->claim->u.deleg_cur.delegate_stateid;
799  else if (open->claim->claim == CLAIM_DELEG_CUR_FH)
800  stateid = open->claim->u.deleg_cur_fh.delegate_stateid;
801  } else if (argop->op == OP_CLOSE) {
803  stateid = close->stateid;
804  } else if (argop->op == OP_READ) {
805  nfs41_read_args *read = (nfs41_read_args*)argop->arg;
806  stateid = read->stateid;
807  } else if (argop->op == OP_WRITE) {
808  nfs41_write_args *write = (nfs41_write_args*)argop->arg;
809  stateid = write->stateid;
810  } else if (argop->op == OP_LOCK) {
811  nfs41_lock_args *lock = (nfs41_lock_args*)argop->arg;
812  if (lock->locker.new_lock_owner)
813  stateid = lock->locker.u.open_owner.open_stateid;
814  else
815  stateid = lock->locker.u.lock_owner.lock_stateid;
816  } else if (argop->op == OP_LOCKU) {
817  nfs41_locku_args *locku = (nfs41_locku_args*)argop->arg;
818  stateid = locku->lock_stateid;
819  } else if (argop->op == OP_SETATTR) {
820  nfs41_setattr_args *setattr = (nfs41_setattr_args*)argop->arg;
821  stateid = setattr->stateid;
822  } else if (argop->op == OP_LAYOUTGET) {
823  pnfs_layoutget_args *lget = (pnfs_layoutget_args*)argop->arg;
824  stateid = lget->stateid;
825  } else if (argop->op == OP_DELEGRETURN) {
827  stateid = dr->stateid;
828  }
829  if (stateid == NULL)
830  return FALSE;
831 
832  /* if there's recovery in progress, wait for it to finish */
833  EnterCriticalSection(&session->client->recovery.lock);
834  while (session->client->recovery.in_recovery)
835  SleepConditionVariableCS(&session->client->recovery.cond,
836  &session->client->recovery.lock, INFINITE);
837  LeaveCriticalSection(&session->client->recovery.lock);
838 
839  switch (stateid->type) {
840  case STATEID_OPEN:
841  return recover_stateid_open(argop, stateid);
842 
843  case STATEID_LOCK:
844  return recover_stateid_lock(argop, stateid);
845 
846  case STATEID_DELEG_FILE:
847  return recover_stateid_delegation(argop, stateid);
848 
849  default:
850  eprintf("%s can't recover stateid type %u\n",
851  nfs_opnum_to_string(argop->op), stateid->type);
852  break;
853  }
854  return FALSE;
855 }
static bool_t recover_stateid_open(IN nfs_argop4 *argop, IN stateid_arg *stateid)
Definition: recovery.c:703
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:54
struct cb_recall recall
#define IN
Definition: typedefs.h:38
enum nfsstat4 nfs41_free_stateid(IN nfs41_session *session, IN stateid4 *stateid)
Definition: nfs41_ops.c:1870
#define TRUE
Definition: types.h:120
static int recover_open(IN nfs41_session *session, IN nfs41_open_state *open, IN OUT bool_t *grace)
Definition: recovery.c:202
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
rwlock_t lock
Definition: tcpcore.h:1163
bool_t nfs41_recover_stateid(IN nfs41_session *session, IN nfs_argop4 *argop)
Definition: recovery.c:788
#define open
Definition: acwin.h:95
int32_t bool_t
Definition: types.h:101
static const WCHAR empty[]
Definition: main.c:49
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define free
Definition: debug_ros.c:5
stateid_arg * stateid
Definition: nfs41_ops.h:782
enum nfsstat4 nfs41_test_stateid(IN nfs41_session *session, IN stateid_arg *stateid_array, IN uint32_t count, OUT uint32_t *status_array)
Definition: nfs41_ops.c:1900
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
enum nfsstat4 nfs41_want_delegation(IN nfs41_session *session, IN nfs41_path_fh *file, IN deleg_claim4 *claim, IN uint32_t want, IN bool_t try_recovery, OUT open_delegation4 *delegation)
Definition: nfs41_ops.c:1624
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
void nfs41_recover_sequence_flags(IN nfs41_session *session, IN uint32_t flags)
Definition: recovery.c:98
struct list_entry delegations
Definition: nfs41.h:188
static int recover_delegation_open(IN nfs41_session *session, IN nfs41_delegation_state *deleg, IN OUT bool_t *grace)
Definition: recovery.c:396
__u16 time
Definition: mkdosfs.c:366
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
static uint32_t stateid_array(IN struct list_entry *delegations, IN struct list_entry *opens, OUT stateid_arg **stateids_out, OUT uint32_t **statuses_out)
Definition: recovery.c:547
static bool_t recover_stateid_lock(IN nfs_argop4 *argop, IN stateid_arg *stateid)
Definition: recovery.c:723
unsigned char owner[NFS4_OPAQUE_LIMIT]
Definition: nfs41_types.h:119
#define write
Definition: acwin.h:97
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static int recover_open_no_grace(IN nfs41_session *session, IN nfs41_path_fh *parent, IN nfs41_path_fh *file, IN state_owner4 *owner, IN uint32_t access, IN uint32_t deny, OUT stateid4 *stateid, OUT open_delegation4 *delegation)
Definition: recovery.c:157
char name[1]
Definition: fci.c:135
VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable)
Definition: sync.c:137
#define list_for_each(entry, head)
Definition: list.h:36
#define dprintf
Definition: regdump.c:33
smooth NULL
Definition: ftsmooth.c:416
uint32_t prev_delegate_type
Definition: nfs41_ops.h:796
bool_t nfs41_recovery_start_or_wait(IN nfs41_client *client)
Definition: recovery.c:34
#define list_container(entry, type, field)
Definition: list.h:33
int nfs41_client_delegation_recovery(IN nfs41_client *client)
Definition: delegation.c:861
#define client_entry(pos)
Definition: namespace.c:33
stateid_arg * stateid
Definition: nfs41_ops.h:377
static int recover_open_grace(IN nfs41_session *session, IN nfs41_path_fh *parent, IN nfs41_path_fh *file, IN state_owner4 *owner, IN uint32_t access, IN uint32_t deny, OUT stateid4 *stateid, OUT open_delegation4 *delegation)
Definition: recovery.c:138
uint32_t owner_len
Definition: nfs41_types.h:118
int nfs41_recover_session(IN nfs41_session *session, IN bool_t client_state_lost)
Definition: recovery.c:69
open_delegation4 state
Definition: nfs41.h:96
r parent
Definition: btrfs.c:2897
if(!(yy_init))
Definition: macro.lex.yy.c:714
enum stateid_type type
Definition: nfs41_ops.h:285
nfs41_delegation_state * delegation
Definition: nfs41_ops.h:287
void nfs41_recovery_finish(IN nfs41_client *client)
Definition: recovery.c:57
enum open_delegation_type4 type
Definition: nfs41_types.h:154
static FILE * client
Definition: client.c:41
static FILE * out
Definition: regtests2xml.c:44
CRITICAL_SECTION lock
Definition: nfs41.h:189
stateid_arg * stateid
Definition: nfs41_ops.h:912
enum dhcp_state state
Definition: dhcpd.h:214
union __open_claim4::@40 u
GLbitfield flags
Definition: glext.h:7161
int nfs41_recover_client_state(IN nfs41_session *session, IN nfs41_client *client)
Definition: recovery.c:487
nfs41_open_state * open
Definition: nfs41_ops.h:286
int nfs41_client_renew(IN nfs41_client *client)
Definition: nfs41_client.c:168
nfsstat4
Definition: nfs41_const.h:86
int nfs41_open(IN nfs41_session *session, IN nfs41_path_fh *parent, IN nfs41_path_fh *file, IN state_owner4 *owner, IN open_claim4 *claim, IN uint32_t allow, IN uint32_t deny, IN uint32_t create, IN uint32_t how_mode, IN OPTIONAL nfs41_file_info *createattrs, IN bool_t try_recovery, OUT stateid4 *stateid, OUT open_delegation4 *delegation, OUT OPTIONAL nfs41_file_info *info)
Definition: nfs41_ops.c:366
static bool_t recover_stateid_delegation(IN nfs_argop4 *argop, IN stateid_arg *stateid)
Definition: recovery.c:752
static int state
Definition: maze.c:121
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:82
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define close
Definition: acwin.h:98
void nfs41_client_state_revoked(IN nfs41_session *session, IN nfs41_client *client, IN uint32_t revoked)
Definition: recovery.c:633
struct __open_claim4::@40::__open_claim_null null
__WINE_SERVER_LIST_INLINE int list_empty(const struct list *list)
Definition: list.h:143
stateid_arg * lock_stateid
Definition: nfs41_ops.h:478
static int recover_delegation_want(IN nfs41_session *session, IN nfs41_delegation_state *deleg, IN OUT bool_t *grace)
Definition: recovery.c:338
__kernel_time_t time_t
Definition: linux.h:252
BOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD Timeout)
Definition: sync.c:105
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
int nfs41_lock(IN nfs41_session *session, IN nfs41_path_fh *file, IN state_owner4 *owner, IN uint32_t type, IN uint64_t offset, IN uint64_t length, IN bool_t reclaim, IN bool_t try_recovery, IN OUT stateid_arg *stateid)
Definition: nfs41_ops.c:904
const char * nfs_opnum_to_string(int opnum)
Definition: daemon_debug.c:305
stateid4 stateid
Definition: nfs41_ops.h:284
int nfs41_close(IN nfs41_session *session, IN nfs41_path_fh *file, IN stateid_arg *stateid)
Definition: nfs41_ops.c:627
Definition: list.h:27
UINT32 uint32_t
Definition: types.h:75
uint32_t claim
Definition: nfs41_ops.h:794
int nfs41_session_renew(IN nfs41_session *session)
struct __open_claim4::@40::__open_claim_deleg_prev deleg_prev
struct list_entry opens
Definition: nfs41.h:187
#define calloc
Definition: rosglue.h:14
uint32_t claim
Definition: nfs41_ops.h:615
#define OUT
Definition: typedefs.h:39
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
static int recover_locks(IN nfs41_session *session, IN nfs41_open_state *open, IN OUT bool_t *grace)
Definition: recovery.c:281
int nfs41_delegation_granted(IN nfs41_session *session, IN nfs41_path_fh *parent, IN nfs41_path_fh *file, IN open_delegation4 *delegation, IN bool_t try_recovery, OUT nfs41_delegation_state **deleg_out)
Definition: delegation.c:330
static int recover_delegation(IN nfs41_session *session, IN nfs41_delegation_state *deleg, IN OUT bool_t *grace, IN OUT bool_t *want_supported)
Definition: recovery.c:460
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
#define open_entry(pos)
Definition: delegation.c:89
#define INFINITE
Definition: serial.h:102
#define memset(x, y, z)
Definition: compat.h:39
static SERVICE_STATUS status
Definition: service.c:31
enum pnfs_status pnfs_file_layout_recall(IN struct __nfs41_client *client, IN const struct cb_layoutrecall_args *recall)
struct __open_claim4::@40::__open_claim_prev prev
VOID WINAPI AcquireSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:61
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:89
enum nfsstat4 nfs41_reclaim_complete(IN nfs41_session *session)
Definition: nfs41_ops.c:268
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
Definition: fci.c:126
Definition: ps.c:97