1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
8
9
10 #include "Cookie.h"
11 #include "FileSystem.h"
12 #include "NFS4Object.h"
13 #include "OpenState.h"
14 #include "Request.h"
15
16
17 static inline bigtime_t
RetryDelay(uint32 attempt,uint32 leaseTime=0)18 RetryDelay(uint32 attempt, uint32 leaseTime = 0)
19 {
20 attempt = min_c(attempt, 10);
21
22 bigtime_t delay = (bigtime_t(1) << (attempt - 1)) * 100000;
23 if (leaseTime != 0)
24 delay = min_c(delay, sSecToBigTime(leaseTime));
25 return delay;
26 }
27
28
29 bool
HandleErrors(uint32 & attempt,uint32 nfs4Error,RPC::Server * server,OpenStateCookie * cookie,OpenState * state,uint32 * sequence)30 NFS4Object::HandleErrors(uint32& attempt, uint32 nfs4Error, RPC::Server* server,
31 OpenStateCookie* cookie, OpenState* state, uint32* sequence)
32 {
33 // No request send by the client should cause any of the following errors.
34 ASSERT(nfs4Error != NFS4ERR_CLID_INUSE);
35 ASSERT(nfs4Error != NFS4ERR_BAD_STATEID);
36 ASSERT(nfs4Error != NFS4ERR_RESTOREFH);
37 ASSERT(nfs4Error != NFS4ERR_LOCKS_HELD);
38 ASSERT(nfs4Error != NFS4ERR_OP_ILLEGAL);
39
40 attempt++;
41
42 if (cookie != NULL)
43 state = cookie->fOpenState;
44
45 uint32 leaseTime;
46 status_t result;
47 switch (nfs4Error) {
48 case NFS4_OK:
49 return false;
50
51 // retransmission of CLOSE caused seqid to fall back
52 case NFS4ERR_BAD_SEQID:
53 if (attempt == 1) {
54 ASSERT(sequence != NULL);
55 (*sequence)++;
56 return true;
57 }
58 return false;
59
60 // resource is locked, we need to wait
61 case NFS4ERR_DENIED:
62 if (cookie == NULL)
63 return false;
64
65 if (sequence != NULL)
66 fFileSystem->OpenOwnerSequenceUnlock(*sequence);
67
68 result = acquire_sem_etc(cookie->fSnoozeCancel, 1,
69 B_RELATIVE_TIMEOUT, RetryDelay(attempt));
70
71 if (sequence != NULL)
72 *sequence = fFileSystem->OpenOwnerSequenceLock();
73
74 if (result != B_TIMED_OUT) {
75 if (result == B_OK)
76 release_sem(cookie->fSnoozeCancel);
77 return false;
78 }
79 return true;
80
81 // server needs more time, we need to wait
82 case NFS4ERR_LOCKED:
83 case NFS4ERR_DELAY:
84 if (sequence != NULL)
85 fFileSystem->OpenOwnerSequenceUnlock(*sequence);
86
87 if (cookie == NULL) {
88 snooze_etc(RetryDelay(attempt), B_SYSTEM_TIMEBASE,
89 B_RELATIVE_TIMEOUT);
90
91
92 if (sequence != NULL)
93 *sequence = fFileSystem->OpenOwnerSequenceLock();
94
95 return true;
96 }
97
98 if ((cookie->fMode & O_NONBLOCK) == 0) {
99 result = acquire_sem_etc(cookie->fSnoozeCancel, 1,
100 B_RELATIVE_TIMEOUT, RetryDelay(attempt));
101
102 if (sequence != NULL)
103 *sequence = fFileSystem->OpenOwnerSequenceLock();
104
105 if (result != B_TIMED_OUT) {
106 if (result == B_OK)
107 release_sem(cookie->fSnoozeCancel);
108 return false;
109 }
110 return true;
111 }
112
113 if (sequence != NULL)
114 *sequence = fFileSystem->OpenOwnerSequenceLock();
115 return false;
116
117 // server is in grace period, we need to wait
118 case NFS4ERR_GRACE:
119 leaseTime = fFileSystem->NFSServer()->LeaseTime();
120 if (sequence != NULL)
121 fFileSystem->OpenOwnerSequenceUnlock(*sequence);
122
123 if (cookie == NULL) {
124 snooze_etc(RetryDelay(attempt, leaseTime), B_SYSTEM_TIMEBASE,
125 B_RELATIVE_TIMEOUT);
126 if (sequence != NULL)
127 *sequence = fFileSystem->OpenOwnerSequenceLock();
128 return true;
129 }
130
131 if ((cookie->fMode & O_NONBLOCK) == 0) {
132 result = acquire_sem_etc(cookie->fSnoozeCancel, 1,
133 B_RELATIVE_TIMEOUT, RetryDelay(attempt, leaseTime));
134
135 if (sequence != NULL)
136 *sequence = fFileSystem->OpenOwnerSequenceLock();
137
138 if (result != B_TIMED_OUT) {
139 if (result == B_OK)
140 release_sem(cookie->fSnoozeCancel);
141 return false;
142 }
143 return true;
144 }
145
146 if (sequence != NULL)
147 *sequence = fFileSystem->OpenOwnerSequenceLock();
148 return false;
149
150 // server has rebooted, reclaim share and try again
151 case NFS4ERR_STALE_CLIENTID:
152 case NFS4ERR_STALE_STATEID:
153 if (state != NULL) {
154 if (sequence != NULL)
155 fFileSystem->OpenOwnerSequenceUnlock(*sequence);
156
157 fFileSystem->NFSServer()->ServerRebooted(state->fClientID);
158 if (sequence != NULL)
159 *sequence = fFileSystem->OpenOwnerSequenceLock();
160
161 return true;
162 }
163 return false;
164
165 // File Handle has expired, is invalid or the node has been deleted
166 case NFS4ERR_BADHANDLE:
167 case NFS4ERR_FHEXPIRED:
168 case NFS4ERR_STALE:
169 if (fInfo.UpdateFileHandles(fFileSystem) == B_OK)
170 return true;
171 return false;
172
173 // filesystem has been moved
174 case NFS4ERR_LEASE_MOVED:
175 case NFS4ERR_MOVED:
176 fFileSystem->Migrate(server);
177 return true;
178
179 // lease has expired
180 case NFS4ERR_EXPIRED:
181 if (state != NULL) {
182 fFileSystem->NFSServer()->ClientId(state->fClientID, true);
183 return true;
184 }
185 return false;
186
187 default:
188 return false;
189 }
190 }
191
192
193 status_t
ConfirmOpen(const FileHandle & fh,OpenState * state,uint32 * sequence)194 NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state,
195 uint32* sequence)
196 {
197 ASSERT(state != NULL);
198 ASSERT(sequence != NULL);
199
200 uint32 attempt = 0;
201 do {
202 RPC::Server* serv = fFileSystem->Server();
203 Request request(serv, fFileSystem);
204
205 RequestBuilder& req = request.Builder();
206
207 req.PutFH(fh);
208 req.OpenConfirm(*sequence, state->fStateID, state->fStateSeq);
209
210 status_t result = request.Send();
211 if (result != B_OK)
212 return result;
213
214 ReplyInterpreter& reply = request.Reply();
215
216 result = reply.PutFH();
217 if (result == B_OK)
218 *sequence += IncrementSequence(reply.NFS4Error());
219
220 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state))
221 continue;
222
223 result = reply.OpenConfirm(&state->fStateSeq);
224 if (result != B_OK)
225 return result;
226
227 return B_OK;
228 } while (true);
229 }
230
231
232 uint32
IncrementSequence(uint32 error)233 NFS4Object::IncrementSequence(uint32 error)
234 {
235 if (error != NFS4ERR_STALE_CLIENTID && error != NFS4ERR_STALE_STATEID
236 && error != NFS4ERR_BAD_STATEID && error != NFS4ERR_BAD_SEQID
237 && error != NFS4ERR_BADXDR && error != NFS4ERR_RESOURCE
238 && error != NFS4ERR_NOFILEHANDLE)
239 return 1;
240
241 return 0;
242 }
243
244