ReactOS  0.4.12-dev-14-gd0c8636
lock.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 <windows.h>
23 #include <stdio.h>
24 
25 #include "daemon_debug.h"
26 #include "delegation.h"
27 #include "nfs41_ops.h"
28 #include "upcall.h"
29 #include "util.h"
30 
31 
32 #define LKLVL 2 /* dprintf level for lock logging */
33 
34 
35 static void lock_stateid_arg(
38 {
39  arg->open = state;
40  arg->delegation = NULL;
41 
42  AcquireSRWLockShared(&state->lock);
43  if (state->locks.stateid.seqid) {
44  memcpy(&arg->stateid, &state->locks.stateid, sizeof(stateid4));
45  arg->type = STATEID_LOCK;
46  } else if (state->do_close) {
47  memcpy(&arg->stateid, &state->stateid, sizeof(stateid4));
48  arg->type = STATEID_OPEN;
49  } else {
50  memset(&arg->stateid, 0, sizeof(stateid4));
51  arg->type = STATEID_SPECIAL;
52  }
53  ReleaseSRWLockShared(&state->lock);
54 }
55 
56 /* expects the caller to hold an exclusive lock on nfs41_open_state.lock */
57 static void lock_stateid_update(
59  IN const stateid4 *stateid)
60 {
61  if (state->locks.stateid.seqid == 0) {
62  /* if it's a new lock stateid, copy it in */
63  memcpy(&state->locks.stateid, stateid, sizeof(stateid4));
64  } else if (stateid->seqid > state->locks.stateid.seqid) {
65  /* update the seqid if it's more recent */
66  state->locks.stateid.seqid = stateid->seqid;
67  }
68 }
69 
70 static void open_lock_add(
72  IN const stateid_arg *stateid,
74 {
75  AcquireSRWLockExclusive(&open->lock);
76 
77  if (stateid->type == STATEID_LOCK)
78  lock_stateid_update(open, &stateid->stateid);
79 
80  lock->id = open->locks.counter++;
81  list_add_tail(&open->locks.list, &lock->open_entry);
82 
83  ReleaseSRWLockExclusive(&open->lock);
84 }
85 
89 {
90  bool_t delegated = FALSE;
91 
92  AcquireSRWLockExclusive(&open->lock);
93  if (open->delegation.state) {
94  nfs41_delegation_state *deleg = open->delegation.state;
95  AcquireSRWLockShared(&deleg->lock);
96  if (deleg->state.type == OPEN_DELEGATE_WRITE
97  && deleg->status == DELEGATION_GRANTED) {
98  lock->delegated = 1;
99  lock->id = open->locks.counter++;
100  list_add_tail(&open->locks.list, &lock->open_entry);
101  delegated = TRUE;
102  }
103  ReleaseSRWLockShared(&deleg->lock);
104  }
105  ReleaseSRWLockExclusive(&open->lock);
106 
107  return delegated;
108 }
109 
110 #define lock_entry(pos) list_container(pos, nfs41_lock_state, open_entry)
111 
112 static int lock_range_cmp(const struct list_entry *entry, const void *value)
113 {
114  const nfs41_lock_state *lhs = lock_entry(entry);
115  const nfs41_lock_state *rhs = (const nfs41_lock_state*)value;
116  if (lhs->offset != rhs->offset) return -1;
117  if (lhs->length != rhs->length) return -1;
118  return 0;
119 }
120 
123  IN const nfs41_lock_state *input)
124 {
125  struct list_entry *entry;
126  int status = ERROR_NOT_LOCKED;
127 
128  AcquireSRWLockExclusive(&open->lock);
129 
130  /* find lock state that matches this range */
131  entry = list_search(&open->locks.list, input, lock_range_cmp);
132  if (entry) {
133  nfs41_lock_state *lock = lock_entry(entry);
134  if (lock->delegated) {
135  /* if the lock was delegated, remove/free it and return success */
136  list_remove(entry);
137  free(lock);
138  status = NO_ERROR;
139  } else
140  status = ERROR_LOCKED;
141  }
142 
143  ReleaseSRWLockExclusive(&open->lock);
144  return status;
145 }
146 
147 static void open_unlock_remove(
149  IN const stateid_arg *stateid,
150  IN const nfs41_lock_state *input)
151 {
152  struct list_entry *entry;
153 
154  AcquireSRWLockExclusive(&open->lock);
155  if (stateid->type == STATEID_LOCK)
156  lock_stateid_update(open, &stateid->stateid);
157 
158  /* find and remove the unlocked range */
159  entry = list_search(&open->locks.list, input, lock_range_cmp);
160  if (entry) {
161  list_remove(entry);
162  free(lock_entry(entry));
163  }
164  ReleaseSRWLockExclusive(&open->lock);
165 }
166 
167 
168 /* NFS41_LOCK */
169 static int parse_lock(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
170 {
171  int status;
172  lock_upcall_args *args = &upcall->args.lock;
173 
174  status = safe_read(&buffer, &length, &args->offset, sizeof(LONGLONG));
175  if (status) goto out;
176  status = safe_read(&buffer, &length, &args->length, sizeof(LONGLONG));
177  if (status) goto out;
178  status = safe_read(&buffer, &length, &args->exclusive, sizeof(BOOLEAN));
179  if (status) goto out;
180  status = safe_read(&buffer, &length, &args->blocking, sizeof(BOOLEAN));
181  if (status) goto out;
182 
183  dprintf(1, "parsing NFS41_LOCK: offset=0x%llx length=0x%llx exclusive=%u "
184  "blocking=%u\n", args->offset, args->length, args->exclusive,
185  args->blocking);
186 out:
187  return status;
188 }
189 
190 static __inline uint32_t get_lock_type(BOOLEAN exclusive, BOOLEAN blocking)
191 {
192  return blocking == 0
193  ? ( exclusive == 0 ? READ_LT : WRITE_LT )
194  : ( exclusive == 0 ? READW_LT : WRITEW_LT );
195 }
196 
198 {
199  stateid_arg stateid;
200  lock_upcall_args *args = &upcall->args.lock;
201  nfs41_open_state *state = upcall->state_ref;
203  const uint32_t type = get_lock_type(args->exclusive, args->blocking);
204  int status = NO_ERROR;
205 
206  /* 18.10.3. Operation 12: LOCK - Create Lock
207  * "To lock the file from a specific offset through the end-of-file
208  * (no matter how long the file actually is) use a length field equal
209  * to NFS4_UINT64_MAX." */
210  if (args->length >= NFS4_UINT64_MAX - args->offset)
211  args->length = NFS4_UINT64_MAX;
212 
213  /* allocate the lock state */
214  lock = calloc(1, sizeof(nfs41_lock_state));
215  if (lock == NULL) {
216  status = GetLastError();
217  goto out;
218  }
219  lock->offset = args->offset;
220  lock->length = args->length;
221  lock->exclusive = args->exclusive;
222 
223  /* if we hold a write delegation, handle the lock locally */
224  if (open_lock_delegate(state, lock)) {
225  dprintf(LKLVL, "delegated lock { %llu, %llu }\n",
226  lock->offset, lock->length);
227  args->acquired = TRUE; /* for cancel_lock() */
228  goto out;
229  }
230 
231  /* open_to_lock_owner4 requires an open stateid; if we
232  * have a delegation, convert it to an open stateid */
233  status = nfs41_delegation_to_open(state, TRUE);
234  if (status) {
235  status = ERROR_FILE_INVALID;
236  goto out_free;
237  }
238 
239  EnterCriticalSection(&state->locks.lock);
240 
241  lock_stateid_arg(state, &stateid);
242 
243  status = nfs41_lock(state->session, &state->file, &state->owner,
244  type, lock->offset, lock->length, FALSE, TRUE, &stateid);
245  if (status) {
246  dprintf(LKLVL, "nfs41_lock failed with %s\n",
247  nfs_error_string(status));
248  status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
249  LeaveCriticalSection(&state->locks.lock);
250  goto out_free;
251  }
252 
253  /* save lock state with the open */
254  open_lock_add(state, &stateid, lock);
255  LeaveCriticalSection(&state->locks.lock);
256 
257  args->acquired = TRUE; /* for cancel_lock() */
258 out:
259  return status;
260 
261 out_free:
262  free(lock);
263  goto out;
264 }
265 
267 {
268  stateid_arg stateid;
270  lock_upcall_args *args = &upcall->args.lock;
271  nfs41_open_state *state = upcall->state_ref;
272  int status = NO_ERROR;
273 
274  dprintf(1, "--> cancel_lock()\n");
275 
276  /* can't do 'if (upcall->status)' here, because a handle_lock() success
277  * could be overwritten by upcall_marshall() or allocation failure */
278  if (!args->acquired)
279  goto out;
280 
281  input.offset = args->offset;
282  input.length = args->length;
283 
284  /* search for the range to unlock, and remove if delegated */
285  status = open_unlock_delegate(state, &input);
286  if (status != ERROR_LOCKED)
287  goto out;
288 
289  EnterCriticalSection(&state->locks.lock);
290  lock_stateid_arg(state, &stateid);
291 
292  status = nfs41_unlock(state->session, &state->file,
293  args->offset, args->length, &stateid);
294 
295  open_unlock_remove(state, &stateid, &input);
296  LeaveCriticalSection(&state->locks.lock);
297 
298  status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
299 out:
300  dprintf(1, "<-- cancel_lock() returning %d\n", status);
301 }
302 
303 
304 /* NFS41_UNLOCK */
305 static int parse_unlock(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
306 {
307  int status;
308  unlock_upcall_args *args = &upcall->args.unlock;
309 
310  status = safe_read(&buffer, &length, &args->count, sizeof(ULONG));
311  if (status) goto out;
312 
313  args->buf = buffer;
314  args->buf_len = length;
315 
316  dprintf(1, "parsing NFS41_UNLOCK: count=%u\n", args->count);
317 out:
318  return status;
319 }
320 
322 {
324  stateid_arg stateid;
325  unlock_upcall_args *args = &upcall->args.unlock;
326  nfs41_open_state *state = upcall->state_ref;
327  unsigned char *buf = args->buf;
328  uint32_t buf_len = args->buf_len;
329  uint32_t i;
330  int status = NO_ERROR;
331 
332  for (i = 0; i < args->count; i++) {
333  if (safe_read(&buf, &buf_len, &input.offset, sizeof(LONGLONG))) break;
334  if (safe_read(&buf, &buf_len, &input.length, sizeof(LONGLONG))) break;
335 
336  /* do the same translation as LOCK, or the ranges won't match */
337  if (input.length >= NFS4_UINT64_MAX - input.offset)
338  input.length = NFS4_UINT64_MAX;
339 
340  /* search for the range to unlock, and remove if delegated */
341  status = open_unlock_delegate(state, &input);
342  if (status != ERROR_LOCKED)
343  continue;
344 
345  EnterCriticalSection(&state->locks.lock);
346  lock_stateid_arg(state, &stateid);
347 
348  status = nfs41_unlock(state->session, &state->file,
349  input.offset, input.length, &stateid);
350 
351  open_unlock_remove(state, &stateid, &input);
352  LeaveCriticalSection(&state->locks.lock);
353 
354  status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
355  }
356  return status;
357 }
358 
359 
361  parse_lock,
362  handle_lock,
363  NULL,
365 };
367  parse_unlock,
369 };
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:54
BOOLEAN exclusive
Definition: upcall.h:79
#define IN
Definition: typedefs.h:38
static int handle_unlock(nfs41_upcall *upcall)
Definition: lock.c:321
int nfs_to_windows_error(int status, int default_error)
Definition: util.c:235
Definition: get.c:139
#define TRUE
Definition: types.h:120
uint64_t offset
Definition: nfs41.h:114
struct __nfs41_open_state::@25 locks
rwlock_t lock
Definition: tcpcore.h:1163
#define open
Definition: acwin.h:71
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
int32_t bool_t
Definition: types.h:101
#define free
Definition: debug_ros.c:5
uint8_t entry
Definition: isohybrid.c:63
const nfs41_upcall_op nfs41_op_lock
Definition: lock.c:360
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
GLuint buffer
Definition: glext.h:5915
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
static int open_unlock_delegate(IN nfs41_open_state *open, IN const nfs41_lock_state *input)
Definition: lock.c:121
#define NO_ERROR
Definition: dderror.h:5
Definition: match.c:390
struct __nfs41_session * session
Definition: nfs41.h:132
lock_upcall_args lock
Definition: upcall.h:180
static int parse_lock(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
Definition: lock.c:169
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
#define ERROR_BAD_NET_RESP
Definition: winerror.h:150
GLenum GLclampf GLint i
Definition: glfuncs.h:14
static int lock_range_cmp(const struct list_entry *entry, const void *value)
Definition: lock.c:112
static void cancel_lock(IN nfs41_upcall *upcall)
Definition: lock.c:266
nfs41_open_state * state_ref
Definition: upcall.h:207
uint32_t count
Definition: upcall.h:85
uint32_t exclusive
Definition: nfs41.h:116
static void lock_stateid_arg(IN nfs41_open_state *state, OUT stateid_arg *arg)
Definition: lock.c:35
#define dprintf
Definition: regdump.c:33
static void open_lock_add(IN nfs41_open_state *open, IN const stateid_arg *stateid, IN nfs41_lock_state *lock)
Definition: lock.c:70
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
static const uint64_t NFS4_UINT64_MAX
Definition: nfs41_types.h:32
static int handle_lock(nfs41_upcall *upcall)
Definition: lock.c:197
unsigned char * buf
Definition: upcall.h:86
int64_t LONGLONG
Definition: typedefs.h:66
int nfs41_delegation_to_open(IN nfs41_open_state *open, IN bool_t try_recovery)
Definition: delegation.c:539
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
const nfs41_upcall_op nfs41_op_unlock
Definition: lock.c:366
static void lock_stateid_update(OUT nfs41_open_state *state, IN const stateid4 *stateid)
Definition: lock.c:57
open_delegation4 state
Definition: nfs41.h:96
upcall_args args
Definition: upcall.h:198
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
uint32_t buf_len
Definition: upcall.h:87
enum open_delegation_type4 type
Definition: nfs41_types.h:154
static FILE * out
Definition: regtests2xml.c:44
const char * nfs_error_string(int status)
Definition: daemon_debug.c:370
unlock_upcall_args unlock
Definition: upcall.h:181
int nfs41_unlock(IN nfs41_session *session, IN nfs41_path_fh *file, IN uint64_t offset, IN uint64_t length, IN OUT stateid_arg *stateid)
Definition: nfs41_ops.c:966
BOOLEAN blocking
Definition: upcall.h:80
uint64_t length
Definition: nfs41.h:115
static int state
Definition: maze.c:121
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:82
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
uint64_t length
Definition: upcall.h:78
static void open_unlock_remove(IN nfs41_open_state *open, IN const stateid_arg *stateid, IN const nfs41_lock_state *input)
Definition: lock.c:147
uint32_t delegated
Definition: nfs41.h:117
static struct list_entry * list_search(const struct list_entry *head, const void *value, list_compare_fn compare)
Definition: list.h:102
GLenum GLenum GLenum input
Definition: glext.h:9031
nfs41_path_fh file
Definition: nfs41.h:130
#define LKLVL
Definition: lock.c:32
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
BOOLEAN acquired
Definition: upcall.h:81
state_owner4 owner
Definition: nfs41.h:136
Definition: list.h:27
UINT32 uint32_t
Definition: types.h:75
enum delegation_status status
Definition: nfs41.h:103
#define ERROR_FILE_INVALID
Definition: winerror.h:585
static bool_t open_lock_delegate(IN nfs41_open_state *open, IN nfs41_lock_state *lock)
Definition: lock.c:86
nfs41_updowncall_list upcall
Definition: nfs41_driver.c:273
#define calloc
Definition: rosglue.h:14
#define OUT
Definition: typedefs.h:39
static __inline uint32_t get_lock_type(BOOLEAN exclusive, BOOLEAN blocking)
Definition: lock.c:190
unsigned int ULONG
Definition: retypes.h:1
#define lock_entry(pos)
Definition: lock.c:110
int safe_read(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len)
Definition: util.c:33
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
#define ERROR_NOT_LOCKED
Definition: winerror.h:230
uint64_t offset
Definition: upcall.h:77
#define memset(x, y, z)
Definition: compat.h:39
static SERVICE_STATUS status
Definition: service.c:31
VOID WINAPI AcquireSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:61
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:89
static int parse_unlock(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
Definition: lock.c:305
#define ERROR_LOCKED
Definition: winerror.h:268
Definition: ps.c:97