/src/samba/source3/locking/posix.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Locking functions |
4 | | Copyright (C) Jeremy Allison 1992-2006 |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | |
19 | | Revision History: |
20 | | |
21 | | POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000. |
22 | | */ |
23 | | |
24 | | #include "includes.h" |
25 | | #include "system/filesys.h" |
26 | | #include "lib/util/server_id.h" |
27 | | #include "locking/proto.h" |
28 | | #include "dbwrap/dbwrap.h" |
29 | | #include "dbwrap/dbwrap_rbt.h" |
30 | | #include "util_tdb.h" |
31 | | #include "smbd/fd_handle.h" |
32 | | |
33 | | #undef DBGC_CLASS |
34 | 0 | #define DBGC_CLASS DBGC_LOCKING |
35 | | |
36 | | /* |
37 | | * The pending close database handle. |
38 | | */ |
39 | | |
40 | | static struct db_context *posix_pending_close_db; |
41 | | |
42 | | /**************************************************************************** |
43 | | First - the functions that deal with the underlying system locks - these |
44 | | functions are used no matter if we're mapping CIFS Windows locks or CIFS |
45 | | POSIX locks onto POSIX. |
46 | | ****************************************************************************/ |
47 | | |
48 | | /**************************************************************************** |
49 | | Utility function to map a lock type correctly depending on the open |
50 | | mode of a file. |
51 | | ****************************************************************************/ |
52 | | |
53 | | static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type) |
54 | 0 | { |
55 | 0 | if ((lock_type == WRITE_LOCK) && !fsp->fsp_flags.can_write) { |
56 | | /* |
57 | | * Many UNIX's cannot get a write lock on a file opened read-only. |
58 | | * Win32 locking semantics allow this. |
59 | | * Do the best we can and attempt a read-only lock. |
60 | | */ |
61 | 0 | DBG_DEBUG("Downgrading write lock to read due to read-only " |
62 | 0 | "file.\n"); |
63 | 0 | return F_RDLCK; |
64 | 0 | } |
65 | | |
66 | | /* |
67 | | * This return should be the most normal, as we attempt |
68 | | * to always open files read/write. |
69 | | */ |
70 | | |
71 | 0 | return (lock_type == READ_LOCK) ? F_RDLCK : F_WRLCK; |
72 | 0 | } |
73 | | |
74 | | /**************************************************************************** |
75 | | Debugging aid :-). |
76 | | ****************************************************************************/ |
77 | | |
78 | | static const char *posix_lock_type_name(int lock_type) |
79 | 0 | { |
80 | 0 | return (lock_type == F_RDLCK) ? "READ" : "WRITE"; |
81 | 0 | } |
82 | | |
83 | | /**************************************************************************** |
84 | | Check to see if the given unsigned lock range is within the possible POSIX |
85 | | range. Modifies the given args to be in range if possible, just returns |
86 | | False if not. |
87 | | ****************************************************************************/ |
88 | | |
89 | 0 | #define SMB_OFF_T_BITS (sizeof(off_t)*8) |
90 | | |
91 | | static bool posix_lock_in_range(off_t *offset_out, off_t *count_out, |
92 | | uint64_t u_offset, uint64_t u_count) |
93 | 0 | { |
94 | 0 | off_t offset = (off_t)u_offset; |
95 | 0 | off_t count = (off_t)u_count; |
96 | | |
97 | | /* |
98 | | * For the type of system we are, attempt to |
99 | | * find the maximum positive lock offset as an off_t. |
100 | | */ |
101 | |
|
102 | | #if defined(MAX_POSITIVE_LOCK_OFFSET) /* Some systems have arbitrary limits. */ |
103 | | |
104 | | off_t max_positive_lock_offset = (MAX_POSITIVE_LOCK_OFFSET); |
105 | | #else |
106 | | /* |
107 | | * In this case off_t is 64 bits, |
108 | | * and the underlying system can handle 64 bit signed locks. |
109 | | */ |
110 | |
|
111 | 0 | off_t mask2 = ((off_t)0x4) << (SMB_OFF_T_BITS-4); |
112 | 0 | off_t mask = (mask2<<1); |
113 | 0 | off_t max_positive_lock_offset = ~mask; |
114 | |
|
115 | 0 | #endif |
116 | | /* |
117 | | * POSIX locks of length zero mean lock to end-of-file. |
118 | | * Win32 locks of length zero are point probes. Ignore |
119 | | * any Win32 locks of length zero. JRA. |
120 | | */ |
121 | |
|
122 | 0 | if (count == 0) { |
123 | 0 | DEBUG(10,("posix_lock_in_range: count = 0, ignoring.\n")); |
124 | 0 | return False; |
125 | 0 | } |
126 | | |
127 | | /* |
128 | | * If the given offset was > max_positive_lock_offset then we cannot map this at all |
129 | | * ignore this lock. |
130 | | */ |
131 | | |
132 | 0 | if (u_offset & ~((uint64_t)max_positive_lock_offset)) { |
133 | 0 | DBG_DEBUG("(offset = %ju) offset > %ju" |
134 | 0 | "and we cannot handle this. Ignoring lock.\n", |
135 | 0 | (uintmax_t)u_offset, |
136 | 0 | (uintmax_t)max_positive_lock_offset); |
137 | 0 | return False; |
138 | 0 | } |
139 | | |
140 | | /* |
141 | | * We must truncate the count to less than max_positive_lock_offset. |
142 | | */ |
143 | | |
144 | 0 | if (u_count & ~((uint64_t)max_positive_lock_offset)) { |
145 | 0 | count = max_positive_lock_offset; |
146 | 0 | } |
147 | | |
148 | | /* |
149 | | * Truncate count to end at max lock offset. |
150 | | */ |
151 | |
|
152 | 0 | if (offset > INT64_MAX - count || |
153 | 0 | offset + count > max_positive_lock_offset) { |
154 | 0 | count = max_positive_lock_offset - offset; |
155 | 0 | } |
156 | | |
157 | | /* |
158 | | * If we ate all the count, ignore this lock. |
159 | | */ |
160 | |
|
161 | 0 | if (count == 0) { |
162 | 0 | DBG_DEBUG("Count = 0. Ignoring lock " |
163 | 0 | "u_offset = %" PRIu64 ", u_count = %" PRIu64 "\n", |
164 | 0 | u_offset, |
165 | 0 | u_count); |
166 | 0 | return False; |
167 | 0 | } |
168 | | |
169 | | /* |
170 | | * The mapping was successful. |
171 | | */ |
172 | | |
173 | 0 | DBG_DEBUG("offset_out = %ju count_out = %ju\n", |
174 | 0 | (uintmax_t)offset, |
175 | 0 | (uintmax_t)count); |
176 | |
|
177 | 0 | *offset_out = offset; |
178 | 0 | *count_out = count; |
179 | |
|
180 | 0 | return True; |
181 | 0 | } |
182 | | |
183 | | /**************************************************************************** |
184 | | Actual function that does POSIX locks. Copes with 64 -> 32 bit cruft and |
185 | | broken NFS implementations. |
186 | | ****************************************************************************/ |
187 | | |
188 | | static bool posix_fcntl_lock(files_struct *fsp, int op, off_t offset, off_t count, int type) |
189 | 0 | { |
190 | 0 | bool ret; |
191 | |
|
192 | 0 | DEBUG(8,("posix_fcntl_lock %d %d %jd %jd %d\n", |
193 | 0 | fsp_get_io_fd(fsp),op,(intmax_t)offset,(intmax_t)count,type)); |
194 | |
|
195 | 0 | ret = SMB_VFS_LOCK(fsp, op, offset, count, type); |
196 | |
|
197 | 0 | if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) { |
198 | |
|
199 | 0 | if ((errno == EINVAL) && |
200 | 0 | (op != F_GETLK && |
201 | 0 | op != F_SETLK && |
202 | 0 | op != F_SETLKW)) { |
203 | 0 | DEBUG(0,("WARNING: OFD locks in use and no kernel " |
204 | 0 | "support. Try setting " |
205 | 0 | "'smbd:force process locks = true' " |
206 | 0 | "in smb.conf\n")); |
207 | 0 | } else { |
208 | 0 | DEBUG(0, ("WARNING: lock request at offset " |
209 | 0 | "%ju, length %ju returned\n", |
210 | 0 | (uintmax_t)offset, (uintmax_t)count)); |
211 | 0 | DEBUGADD(0, ("an %s error. This can happen when using 64 bit " |
212 | 0 | "lock offsets\n", strerror(errno))); |
213 | 0 | DEBUGADD(0, ("on 32 bit NFS mounted file systems.\n")); |
214 | 0 | } |
215 | | |
216 | | /* |
217 | | * If the offset is > 0x7FFFFFFF then this will cause problems on |
218 | | * 32 bit NFS mounted filesystems. Just ignore it. |
219 | | */ |
220 | |
|
221 | 0 | if (offset & ~((off_t)0x7fffffff)) { |
222 | 0 | DEBUG(0,("Offset greater than 31 bits. Returning success.\n")); |
223 | 0 | return True; |
224 | 0 | } |
225 | | |
226 | 0 | if (count & ~((off_t)0x7fffffff)) { |
227 | | /* 32 bit NFS file system, retry with smaller offset */ |
228 | 0 | DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n")); |
229 | 0 | errno = 0; |
230 | 0 | count &= 0x7fffffff; |
231 | 0 | ret = SMB_VFS_LOCK(fsp, op, offset, count, type); |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | 0 | DEBUG(8,("posix_fcntl_lock: Lock call %s\n", ret ? "successful" : "failed")); |
236 | 0 | return ret; |
237 | 0 | } |
238 | | |
239 | | /**************************************************************************** |
240 | | Actual function that gets POSIX locks. Copes with 64 -> 32 bit cruft and |
241 | | broken NFS implementations. |
242 | | ****************************************************************************/ |
243 | | |
244 | | static bool posix_fcntl_getlock(files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype) |
245 | 0 | { |
246 | 0 | pid_t pid; |
247 | 0 | bool ret; |
248 | |
|
249 | 0 | DEBUG(8, ("posix_fcntl_getlock %d %ju %ju %d\n", |
250 | 0 | fsp_get_io_fd(fsp), (uintmax_t)*poffset, (uintmax_t)*pcount, |
251 | 0 | *ptype)); |
252 | |
|
253 | 0 | ret = SMB_VFS_GETLOCK(fsp, poffset, pcount, ptype, &pid); |
254 | |
|
255 | 0 | if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) { |
256 | |
|
257 | 0 | DEBUG(0, ("posix_fcntl_getlock: WARNING: lock request at " |
258 | 0 | "offset %ju, length %ju returned\n", |
259 | 0 | (uintmax_t)*poffset, (uintmax_t)*pcount)); |
260 | 0 | DEBUGADD(0, ("an %s error. This can happen when using 64 bit " |
261 | 0 | "lock offsets\n", strerror(errno))); |
262 | 0 | DEBUGADD(0, ("on 32 bit NFS mounted file systems.\n")); |
263 | | |
264 | | /* |
265 | | * If the offset is > 0x7FFFFFFF then this will cause problems on |
266 | | * 32 bit NFS mounted filesystems. Just ignore it. |
267 | | */ |
268 | |
|
269 | 0 | if (*poffset & ~((off_t)0x7fffffff)) { |
270 | 0 | DEBUG(0,("Offset greater than 31 bits. Returning success.\n")); |
271 | 0 | return True; |
272 | 0 | } |
273 | | |
274 | 0 | if (*pcount & ~((off_t)0x7fffffff)) { |
275 | | /* 32 bit NFS file system, retry with smaller offset */ |
276 | 0 | DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n")); |
277 | 0 | errno = 0; |
278 | 0 | *pcount &= 0x7fffffff; |
279 | 0 | ret = SMB_VFS_GETLOCK(fsp,poffset,pcount,ptype,&pid); |
280 | 0 | } |
281 | 0 | } |
282 | | |
283 | 0 | DEBUG(8,("posix_fcntl_getlock: Lock query call %s\n", ret ? "successful" : "failed")); |
284 | 0 | return ret; |
285 | 0 | } |
286 | | |
287 | | /**************************************************************************** |
288 | | POSIX function to see if a file region is locked. Returns True if the |
289 | | region is locked, False otherwise. |
290 | | ****************************************************************************/ |
291 | | |
292 | | bool is_posix_locked(files_struct *fsp, |
293 | | uint64_t *pu_offset, |
294 | | uint64_t *pu_count, |
295 | | enum brl_type *plock_type, |
296 | | enum brl_flavour lock_flav) |
297 | 0 | { |
298 | 0 | off_t offset; |
299 | 0 | off_t count; |
300 | 0 | int posix_lock_type = map_posix_lock_type(fsp,*plock_type); |
301 | |
|
302 | 0 | DBG_DEBUG("File %s, offset = %" PRIu64 ", count = %" PRIu64 ", " |
303 | 0 | "type = %s\n", |
304 | 0 | fsp_str_dbg(fsp), |
305 | 0 | *pu_offset, |
306 | 0 | *pu_count, |
307 | 0 | posix_lock_type_name(*plock_type)); |
308 | | |
309 | | /* |
310 | | * If the requested lock won't fit in the POSIX range, we will |
311 | | * never set it, so presume it is not locked. |
312 | | */ |
313 | |
|
314 | 0 | if(!posix_lock_in_range(&offset, &count, *pu_offset, *pu_count)) { |
315 | 0 | return False; |
316 | 0 | } |
317 | | |
318 | 0 | if (!posix_fcntl_getlock(fsp,&offset,&count,&posix_lock_type)) { |
319 | 0 | return False; |
320 | 0 | } |
321 | | |
322 | 0 | if (posix_lock_type == F_UNLCK) { |
323 | 0 | return False; |
324 | 0 | } |
325 | | |
326 | 0 | if (lock_flav == POSIX_LOCK) { |
327 | | /* Only POSIX lock queries need to know the details. */ |
328 | 0 | *pu_offset = (uint64_t)offset; |
329 | 0 | *pu_count = (uint64_t)count; |
330 | 0 | *plock_type = (posix_lock_type == F_RDLCK) ? READ_LOCK : WRITE_LOCK; |
331 | 0 | } |
332 | 0 | return True; |
333 | 0 | } |
334 | | |
335 | | /**************************************************************************** |
336 | | Next - the functions that deal with in memory database storing representations |
337 | | of either Windows CIFS locks or POSIX CIFS locks. |
338 | | ****************************************************************************/ |
339 | | |
340 | | /* The key used in the in-memory POSIX databases. */ |
341 | | |
342 | | struct lock_ref_count_key { |
343 | | struct file_id id; |
344 | | char r; |
345 | | }; |
346 | | |
347 | | /******************************************************************* |
348 | | Form a static locking key for a dev/inode pair for the lock ref count |
349 | | ******************************************************************/ |
350 | | |
351 | | static TDB_DATA locking_ref_count_key_fsp(const files_struct *fsp, |
352 | | struct lock_ref_count_key *tmp) |
353 | 0 | { |
354 | 0 | ZERO_STRUCTP(tmp); |
355 | 0 | tmp->id = fsp->file_id; |
356 | 0 | tmp->r = 'r'; |
357 | 0 | return make_tdb_data((uint8_t *)tmp, sizeof(*tmp)); |
358 | 0 | } |
359 | | |
360 | | /******************************************************************* |
361 | | Convenience function to get an fd_array key from an fsp. |
362 | | ******************************************************************/ |
363 | | |
364 | | static TDB_DATA fd_array_key_fsp(const files_struct *fsp) |
365 | 0 | { |
366 | 0 | return make_tdb_data((const uint8_t *)&fsp->file_id, sizeof(fsp->file_id)); |
367 | 0 | } |
368 | | |
369 | | /******************************************************************* |
370 | | Create the in-memory POSIX lock databases. |
371 | | ********************************************************************/ |
372 | | |
373 | | bool posix_locking_init(bool read_only) |
374 | 0 | { |
375 | 0 | if (posix_pending_close_db != NULL) { |
376 | 0 | return true; |
377 | 0 | } |
378 | | |
379 | 0 | posix_pending_close_db = db_open_rbt(NULL); |
380 | |
|
381 | 0 | if (posix_pending_close_db == NULL) { |
382 | 0 | DEBUG(0,("Failed to open POSIX pending close database.\n")); |
383 | 0 | return false; |
384 | 0 | } |
385 | | |
386 | 0 | return true; |
387 | 0 | } |
388 | | |
389 | | /******************************************************************* |
390 | | Delete the in-memory POSIX lock databases. |
391 | | ********************************************************************/ |
392 | | |
393 | | bool posix_locking_end(void) |
394 | 0 | { |
395 | | /* |
396 | | * Shouldn't we close all fd's here? |
397 | | */ |
398 | 0 | TALLOC_FREE(posix_pending_close_db); |
399 | 0 | return true; |
400 | 0 | } |
401 | | |
402 | | /**************************************************************************** |
403 | | Next - the functions that deal with reference count of number of locks open |
404 | | on a dev/ino pair. |
405 | | ****************************************************************************/ |
406 | | |
407 | | /**************************************************************************** |
408 | | Increase the lock ref count. Creates lock_ref_count entry if it doesn't exist. |
409 | | ****************************************************************************/ |
410 | | |
411 | | static void increment_lock_ref_count(const files_struct *fsp) |
412 | 0 | { |
413 | 0 | struct lock_ref_count_key tmp; |
414 | 0 | int32_t lock_ref_count = 0; |
415 | 0 | NTSTATUS status; |
416 | |
|
417 | 0 | status = dbwrap_change_int32_atomic( |
418 | 0 | posix_pending_close_db, locking_ref_count_key_fsp(fsp, &tmp), |
419 | 0 | &lock_ref_count, 1); |
420 | |
|
421 | 0 | SMB_ASSERT(NT_STATUS_IS_OK(status)); |
422 | 0 | SMB_ASSERT(lock_ref_count < INT32_MAX); |
423 | | |
424 | 0 | DEBUG(10,("lock_ref_count for file %s = %d\n", |
425 | 0 | fsp_str_dbg(fsp), (int)(lock_ref_count + 1))); |
426 | 0 | } |
427 | | |
428 | | /**************************************************************************** |
429 | | Reduce the lock ref count. |
430 | | ****************************************************************************/ |
431 | | |
432 | | static void decrement_lock_ref_count(const files_struct *fsp) |
433 | 0 | { |
434 | 0 | struct lock_ref_count_key tmp; |
435 | 0 | int32_t lock_ref_count = 0; |
436 | 0 | NTSTATUS status; |
437 | |
|
438 | 0 | status = dbwrap_change_int32_atomic( |
439 | 0 | posix_pending_close_db, locking_ref_count_key_fsp(fsp, &tmp), |
440 | 0 | &lock_ref_count, -1); |
441 | |
|
442 | 0 | SMB_ASSERT(NT_STATUS_IS_OK(status)); |
443 | 0 | SMB_ASSERT(lock_ref_count > 0); |
444 | | |
445 | 0 | DEBUG(10,("lock_ref_count for file %s = %d\n", |
446 | 0 | fsp_str_dbg(fsp), (int)(lock_ref_count - 1))); |
447 | 0 | } |
448 | | |
449 | | /**************************************************************************** |
450 | | Fetch the lock ref count. |
451 | | ****************************************************************************/ |
452 | | |
453 | | static int32_t get_lock_ref_count(const files_struct *fsp) |
454 | 0 | { |
455 | 0 | struct lock_ref_count_key tmp; |
456 | 0 | NTSTATUS status; |
457 | 0 | int32_t lock_ref_count = 0; |
458 | |
|
459 | 0 | status = dbwrap_fetch_int32( |
460 | 0 | posix_pending_close_db, locking_ref_count_key_fsp(fsp, &tmp), |
461 | 0 | &lock_ref_count); |
462 | |
|
463 | 0 | if (!NT_STATUS_IS_OK(status) && |
464 | 0 | !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { |
465 | 0 | DEBUG(0, ("Error fetching " |
466 | 0 | "lock ref count for file %s: %s\n", |
467 | 0 | fsp_str_dbg(fsp), nt_errstr(status))); |
468 | 0 | } |
469 | 0 | return lock_ref_count; |
470 | 0 | } |
471 | | |
472 | | /**************************************************************************** |
473 | | Delete a lock_ref_count entry. |
474 | | ****************************************************************************/ |
475 | | |
476 | | static void delete_lock_ref_count(const files_struct *fsp) |
477 | 0 | { |
478 | 0 | struct lock_ref_count_key tmp; |
479 | | |
480 | | /* Not a bug if it doesn't exist - no locks were ever granted. */ |
481 | |
|
482 | 0 | dbwrap_delete(posix_pending_close_db, |
483 | 0 | locking_ref_count_key_fsp(fsp, &tmp)); |
484 | |
|
485 | 0 | DEBUG(10,("delete_lock_ref_count for file %s\n", |
486 | 0 | fsp_str_dbg(fsp))); |
487 | 0 | } |
488 | | |
489 | | /**************************************************************************** |
490 | | Next - the functions that deal with storing fd's that have outstanding |
491 | | POSIX locks when closed. |
492 | | ****************************************************************************/ |
493 | | |
494 | | /**************************************************************************** |
495 | | The records in posix_pending_close_db are composed of an array of |
496 | | ints keyed by dev/ino pair. Those ints are the fd's that were open on |
497 | | this dev/ino pair that should have been closed, but can't as the lock |
498 | | ref count is non zero. |
499 | | ****************************************************************************/ |
500 | | |
501 | | struct add_fd_to_close_entry_state { |
502 | | const struct files_struct *fsp; |
503 | | }; |
504 | | |
505 | | static void add_fd_to_close_entry_fn( |
506 | | struct db_record *rec, |
507 | | TDB_DATA value, |
508 | | void *private_data) |
509 | 0 | { |
510 | 0 | struct add_fd_to_close_entry_state *state = private_data; |
511 | 0 | int fd = fsp_get_pathref_fd(state->fsp); |
512 | 0 | TDB_DATA values[] = { |
513 | 0 | value, |
514 | 0 | { .dptr = (uint8_t *)&fd, |
515 | 0 | .dsize = sizeof(fd) }, |
516 | 0 | }; |
517 | 0 | NTSTATUS status; |
518 | |
|
519 | 0 | SMB_ASSERT((values[0].dsize % sizeof(int)) == 0); |
520 | | |
521 | 0 | status = dbwrap_record_storev(rec, values, ARRAY_SIZE(values), 0); |
522 | 0 | SMB_ASSERT(NT_STATUS_IS_OK(status)); |
523 | 0 | } |
524 | | |
525 | | /**************************************************************************** |
526 | | Add an fd to the pending close db. |
527 | | ****************************************************************************/ |
528 | | |
529 | | static void add_fd_to_close_entry(const files_struct *fsp) |
530 | 0 | { |
531 | 0 | struct add_fd_to_close_entry_state state = { .fsp = fsp }; |
532 | 0 | NTSTATUS status; |
533 | |
|
534 | 0 | status = dbwrap_do_locked( |
535 | 0 | posix_pending_close_db, |
536 | 0 | fd_array_key_fsp(fsp), |
537 | 0 | add_fd_to_close_entry_fn, |
538 | 0 | &state); |
539 | 0 | SMB_ASSERT(NT_STATUS_IS_OK(status)); |
540 | | |
541 | 0 | DBG_DEBUG("added fd %d file %s\n", |
542 | 0 | fsp_get_pathref_fd(fsp), |
543 | 0 | fsp_str_dbg(fsp)); |
544 | 0 | } |
545 | | |
546 | | static void fd_close_posix_fn( |
547 | | struct db_record *rec, |
548 | | TDB_DATA data, |
549 | | void *private_data) |
550 | 0 | { |
551 | 0 | int *saved_errno = (int *)private_data; |
552 | 0 | size_t num_fds, i; |
553 | |
|
554 | 0 | SMB_ASSERT((data.dsize % sizeof(int)) == 0); |
555 | 0 | num_fds = data.dsize / sizeof(int); |
556 | |
|
557 | 0 | for (i=0; i<num_fds; i++) { |
558 | 0 | int fd; |
559 | 0 | int ret; |
560 | 0 | memcpy(&fd, data.dptr, sizeof(int)); |
561 | 0 | ret = close(fd); |
562 | 0 | if (ret == -1) { |
563 | 0 | *saved_errno = errno; |
564 | 0 | } |
565 | 0 | data.dptr += sizeof(int); |
566 | 0 | } |
567 | 0 | dbwrap_record_delete(rec); |
568 | 0 | } |
569 | | |
570 | | /**************************************************************************** |
571 | | Deal with pending closes needed by POSIX locking support. |
572 | | Note that locking_close_file() is expected to have been called |
573 | | to delete all locks on this fsp before this function is called. |
574 | | ****************************************************************************/ |
575 | | |
576 | | int fd_close_posix(const struct files_struct *fsp) |
577 | 0 | { |
578 | 0 | int saved_errno = 0; |
579 | 0 | int ret; |
580 | 0 | NTSTATUS status; |
581 | |
|
582 | 0 | if (!lp_locking(fsp->conn->params) || |
583 | 0 | !lp_posix_locking(fsp->conn->params) || |
584 | 0 | fsp->fsp_flags.use_ofd_locks) |
585 | 0 | { |
586 | | /* |
587 | | * No locking or POSIX to worry about or we are using POSIX |
588 | | * open file description lock semantics which only removes |
589 | | * locks on the file descriptor we're closing. Just close. |
590 | | */ |
591 | 0 | return close(fsp_get_pathref_fd(fsp)); |
592 | 0 | } |
593 | | |
594 | 0 | if (get_lock_ref_count(fsp)) { |
595 | | |
596 | | /* |
597 | | * There are outstanding locks on this dev/inode pair on |
598 | | * other fds. Add our fd to the pending close db. We also |
599 | | * set fsp_get_io_fd(fsp) to -1 inside fd_close() after returning |
600 | | * from VFS layer. |
601 | | */ |
602 | |
|
603 | 0 | add_fd_to_close_entry(fsp); |
604 | 0 | return 0; |
605 | 0 | } |
606 | | |
607 | 0 | status = dbwrap_do_locked( |
608 | 0 | posix_pending_close_db, |
609 | 0 | fd_array_key_fsp(fsp), |
610 | 0 | fd_close_posix_fn, |
611 | 0 | &saved_errno); |
612 | 0 | if (!NT_STATUS_IS_OK(status)) { |
613 | 0 | DBG_WARNING("dbwrap_do_locked failed: %s\n", |
614 | 0 | nt_errstr(status)); |
615 | 0 | } |
616 | | |
617 | | /* Don't need a lock ref count on this dev/ino anymore. */ |
618 | 0 | delete_lock_ref_count(fsp); |
619 | | |
620 | | /* |
621 | | * Finally close the fd associated with this fsp. |
622 | | */ |
623 | |
|
624 | 0 | ret = close(fsp_get_pathref_fd(fsp)); |
625 | |
|
626 | 0 | if (ret == 0 && saved_errno != 0) { |
627 | 0 | errno = saved_errno; |
628 | 0 | ret = -1; |
629 | 0 | } |
630 | |
|
631 | 0 | return ret; |
632 | 0 | } |
633 | | |
634 | | /**************************************************************************** |
635 | | Next - the functions that deal with the mapping CIFS Windows locks onto |
636 | | the underlying system POSIX locks. |
637 | | ****************************************************************************/ |
638 | | |
639 | | /* |
640 | | * Structure used when splitting a lock range |
641 | | * into a POSIX lock range. Doubly linked list. |
642 | | */ |
643 | | |
644 | | struct lock_list { |
645 | | struct lock_list *next; |
646 | | struct lock_list *prev; |
647 | | off_t start; |
648 | | off_t size; |
649 | | }; |
650 | | |
651 | | /**************************************************************************** |
652 | | Create a list of lock ranges that don't overlap a given range. Used in calculating |
653 | | POSIX locks and unlocks. This is a difficult function that requires ASCII art to |
654 | | understand it :-). |
655 | | ****************************************************************************/ |
656 | | |
657 | | static struct lock_list *posix_lock_list(TALLOC_CTX *ctx, |
658 | | struct lock_list *lhead, |
659 | | const struct lock_context *lock_ctx, /* Lock context lhead belongs to. */ |
660 | | const struct lock_struct *plocks, |
661 | | int num_locks) |
662 | 0 | { |
663 | 0 | int i; |
664 | | |
665 | | /* |
666 | | * Check the current lock list on this dev/inode pair. |
667 | | * Quit if the list is deleted. |
668 | | */ |
669 | |
|
670 | 0 | DEBUG(10, ("posix_lock_list: curr: start=%ju,size=%ju\n", |
671 | 0 | (uintmax_t)lhead->start, (uintmax_t)lhead->size )); |
672 | |
|
673 | 0 | for (i=0; i<num_locks && lhead; i++) { |
674 | 0 | const struct lock_struct *lock = &plocks[i]; |
675 | 0 | struct lock_list *l_curr; |
676 | | |
677 | | /* Ignore all but read/write locks. */ |
678 | 0 | if (lock->lock_type != READ_LOCK && lock->lock_type != WRITE_LOCK) { |
679 | 0 | continue; |
680 | 0 | } |
681 | | |
682 | | /* Ignore locks not owned by this process. */ |
683 | 0 | if (!server_id_equal(&lock->context.pid, &lock_ctx->pid)) { |
684 | 0 | continue; |
685 | 0 | } |
686 | | |
687 | | /* |
688 | | * Walk the lock list, checking for overlaps. Note that |
689 | | * the lock list can expand within this loop if the current |
690 | | * range being examined needs to be split. |
691 | | */ |
692 | | |
693 | 0 | for (l_curr = lhead; l_curr;) { |
694 | |
|
695 | 0 | DEBUG(10, ("posix_lock_list: lock: fnum=%ju: " |
696 | 0 | "start=%ju,size=%ju:type=%s", |
697 | 0 | (uintmax_t)lock->fnum, |
698 | 0 | (uintmax_t)lock->start, |
699 | 0 | (uintmax_t)lock->size, |
700 | 0 | posix_lock_type_name(lock->lock_type) )); |
701 | |
|
702 | 0 | if ( (l_curr->start >= (lock->start + lock->size)) || |
703 | 0 | (lock->start >= (l_curr->start + l_curr->size))) { |
704 | | |
705 | | /* No overlap with existing lock - leave this range alone. */ |
706 | | /********************************************* |
707 | | +---------+ |
708 | | | l_curr | |
709 | | +---------+ |
710 | | +-------+ |
711 | | | lock | |
712 | | +-------+ |
713 | | OR.... |
714 | | +---------+ |
715 | | | l_curr | |
716 | | +---------+ |
717 | | **********************************************/ |
718 | |
|
719 | 0 | DEBUG(10,(" no overlap case.\n" )); |
720 | |
|
721 | 0 | l_curr = l_curr->next; |
722 | |
|
723 | 0 | } else if ( (l_curr->start >= lock->start) && |
724 | 0 | (l_curr->start + l_curr->size <= lock->start + lock->size) ) { |
725 | | |
726 | | /* |
727 | | * This range is completely overlapped by this existing lock range |
728 | | * and thus should have no effect. Delete it from the list. |
729 | | */ |
730 | | /********************************************* |
731 | | +---------+ |
732 | | | l_curr | |
733 | | +---------+ |
734 | | +---------------------------+ |
735 | | | lock | |
736 | | +---------------------------+ |
737 | | **********************************************/ |
738 | | /* Save the next pointer */ |
739 | 0 | struct lock_list *ul_next = l_curr->next; |
740 | |
|
741 | 0 | DEBUG(10,(" delete case.\n" )); |
742 | |
|
743 | 0 | DLIST_REMOVE(lhead, l_curr); |
744 | 0 | if(lhead == NULL) { |
745 | 0 | break; /* No more list... */ |
746 | 0 | } |
747 | | |
748 | 0 | l_curr = ul_next; |
749 | |
|
750 | 0 | } else if ( (l_curr->start >= lock->start) && |
751 | 0 | (l_curr->start < lock->start + lock->size) && |
752 | 0 | (l_curr->start + l_curr->size > lock->start + lock->size) ) { |
753 | | |
754 | | /* |
755 | | * This range overlaps the existing lock range at the high end. |
756 | | * Truncate by moving start to existing range end and reducing size. |
757 | | */ |
758 | | /********************************************* |
759 | | +---------------+ |
760 | | | l_curr | |
761 | | +---------------+ |
762 | | +---------------+ |
763 | | | lock | |
764 | | +---------------+ |
765 | | BECOMES.... |
766 | | +-------+ |
767 | | | l_curr| |
768 | | +-------+ |
769 | | **********************************************/ |
770 | |
|
771 | 0 | l_curr->size = (l_curr->start + l_curr->size) - (lock->start + lock->size); |
772 | 0 | l_curr->start = lock->start + lock->size; |
773 | |
|
774 | 0 | DEBUG(10, (" truncate high case: start=%ju," |
775 | 0 | "size=%ju\n", |
776 | 0 | (uintmax_t)l_curr->start, |
777 | 0 | (uintmax_t)l_curr->size )); |
778 | |
|
779 | 0 | l_curr = l_curr->next; |
780 | |
|
781 | 0 | } else if ( (l_curr->start < lock->start) && |
782 | 0 | (l_curr->start + l_curr->size > lock->start) && |
783 | 0 | (l_curr->start + l_curr->size <= lock->start + lock->size) ) { |
784 | | |
785 | | /* |
786 | | * This range overlaps the existing lock range at the low end. |
787 | | * Truncate by reducing size. |
788 | | */ |
789 | | /********************************************* |
790 | | +---------------+ |
791 | | | l_curr | |
792 | | +---------------+ |
793 | | +---------------+ |
794 | | | lock | |
795 | | +---------------+ |
796 | | BECOMES.... |
797 | | +-------+ |
798 | | | l_curr| |
799 | | +-------+ |
800 | | **********************************************/ |
801 | |
|
802 | 0 | l_curr->size = lock->start - l_curr->start; |
803 | |
|
804 | 0 | DEBUG(10, (" truncate low case: start=%ju," |
805 | 0 | "size=%ju\n", |
806 | 0 | (uintmax_t)l_curr->start, |
807 | 0 | (uintmax_t)l_curr->size )); |
808 | |
|
809 | 0 | l_curr = l_curr->next; |
810 | |
|
811 | 0 | } else if ( (l_curr->start < lock->start) && |
812 | 0 | (l_curr->start + l_curr->size > lock->start + lock->size) ) { |
813 | | /* |
814 | | * Worst case scenario. Range completely overlaps an existing |
815 | | * lock range. Split the request into two, push the new (upper) request |
816 | | * into the dlink list, and continue with the entry after l_new (as we |
817 | | * know that l_new will not overlap with this lock). |
818 | | */ |
819 | | /********************************************* |
820 | | +---------------------------+ |
821 | | | l_curr | |
822 | | +---------------------------+ |
823 | | +---------+ |
824 | | | lock | |
825 | | +---------+ |
826 | | BECOMES..... |
827 | | +-------+ +---------+ |
828 | | | l_curr| | l_new | |
829 | | +-------+ +---------+ |
830 | | **********************************************/ |
831 | 0 | struct lock_list *l_new = talloc(ctx, struct lock_list); |
832 | |
|
833 | 0 | if(l_new == NULL) { |
834 | 0 | DEBUG(0,("posix_lock_list: talloc fail.\n")); |
835 | 0 | return NULL; /* The TALLOC_FREE takes care of cleanup. */ |
836 | 0 | } |
837 | | |
838 | 0 | ZERO_STRUCTP(l_new); |
839 | 0 | l_new->start = lock->start + lock->size; |
840 | 0 | l_new->size = l_curr->start + l_curr->size - l_new->start; |
841 | | |
842 | | /* Truncate the l_curr. */ |
843 | 0 | l_curr->size = lock->start - l_curr->start; |
844 | |
|
845 | 0 | DEBUG(10, (" split case: curr: start=%ju," |
846 | 0 | "size=%ju new: start=%ju," |
847 | 0 | "size=%ju\n", |
848 | 0 | (uintmax_t)l_curr->start, |
849 | 0 | (uintmax_t)l_curr->size, |
850 | 0 | (uintmax_t)l_new->start, |
851 | 0 | (uintmax_t)l_new->size )); |
852 | | |
853 | | /* |
854 | | * Add into the dlink list after the l_curr point - NOT at lhead. |
855 | | */ |
856 | 0 | DLIST_ADD_AFTER(lhead, l_new, l_curr); |
857 | | |
858 | | /* And move after the link we added. */ |
859 | 0 | l_curr = l_new->next; |
860 | |
|
861 | 0 | } else { |
862 | | |
863 | | /* |
864 | | * This logic case should never happen. Ensure this is the |
865 | | * case by forcing an abort.... Remove in production. |
866 | | */ |
867 | 0 | char *msg = NULL; |
868 | |
|
869 | 0 | if (asprintf(&msg, "logic flaw in cases: " |
870 | 0 | "l_curr: start = %ju, " |
871 | 0 | "size = %ju : lock: " |
872 | 0 | "start = %ju, size = %ju", |
873 | 0 | (uintmax_t)l_curr->start, |
874 | 0 | (uintmax_t)l_curr->size, |
875 | 0 | (uintmax_t)lock->start, |
876 | 0 | (uintmax_t)lock->size ) != -1) { |
877 | 0 | smb_panic(msg); |
878 | 0 | } else { |
879 | 0 | smb_panic("posix_lock_list"); |
880 | 0 | } |
881 | 0 | } |
882 | 0 | } /* end for ( l_curr = lhead; l_curr;) */ |
883 | 0 | } /* end for (i=0; i<num_locks && ul_head; i++) */ |
884 | | |
885 | 0 | return lhead; |
886 | 0 | } |
887 | | |
888 | | /**************************************************************************** |
889 | | POSIX function to acquire a lock. Returns True if the |
890 | | lock could be granted, False if not. |
891 | | ****************************************************************************/ |
892 | | |
893 | | bool set_posix_lock_windows_flavour(files_struct *fsp, |
894 | | uint64_t u_offset, |
895 | | uint64_t u_count, |
896 | | enum brl_type lock_type, |
897 | | const struct lock_context *lock_ctx, |
898 | | const struct lock_struct *plocks, |
899 | | int num_locks, |
900 | | int *errno_ret) |
901 | 0 | { |
902 | 0 | off_t offset; |
903 | 0 | off_t count; |
904 | 0 | int posix_lock_type = map_posix_lock_type(fsp,lock_type); |
905 | 0 | bool ret = True; |
906 | 0 | size_t lock_count; |
907 | 0 | TALLOC_CTX *l_ctx = NULL; |
908 | 0 | struct lock_list *llist = NULL; |
909 | 0 | struct lock_list *ll = NULL; |
910 | |
|
911 | 0 | DEBUG(5, ("set_posix_lock_windows_flavour: File %s, offset = %ju, " |
912 | 0 | "count = %ju, type = %s\n", fsp_str_dbg(fsp), |
913 | 0 | (uintmax_t)u_offset, (uintmax_t)u_count, |
914 | 0 | posix_lock_type_name(lock_type))); |
915 | | |
916 | | /* |
917 | | * If the requested lock won't fit in the POSIX range, we will |
918 | | * pretend it was successful. |
919 | | */ |
920 | |
|
921 | 0 | if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) { |
922 | 0 | increment_lock_ref_count(fsp); |
923 | 0 | return True; |
924 | 0 | } |
925 | | |
926 | | /* |
927 | | * Windows is very strange. It allows read locks to be overlaid |
928 | | * (even over a write lock), but leaves the write lock in force until the first |
929 | | * unlock. It also reference counts the locks. This means the following sequence : |
930 | | * |
931 | | * process1 process2 |
932 | | * ------------------------------------------------------------------------ |
933 | | * WRITE LOCK : start = 2, len = 10 |
934 | | * READ LOCK: start =0, len = 10 - FAIL |
935 | | * READ LOCK : start = 0, len = 14 |
936 | | * READ LOCK: start =0, len = 10 - FAIL |
937 | | * UNLOCK : start = 2, len = 10 |
938 | | * READ LOCK: start =0, len = 10 - OK |
939 | | * |
940 | | * Under POSIX, the same sequence in steps 1 and 2 would not be reference counted, but |
941 | | * would leave a single read lock over the 0-14 region. |
942 | | */ |
943 | | |
944 | 0 | if ((l_ctx = talloc_init("set_posix_lock")) == NULL) { |
945 | 0 | DEBUG(0,("set_posix_lock_windows_flavour: unable to init talloc context.\n")); |
946 | 0 | return False; |
947 | 0 | } |
948 | | |
949 | 0 | if ((ll = talloc(l_ctx, struct lock_list)) == NULL) { |
950 | 0 | DEBUG(0,("set_posix_lock_windows_flavour: unable to talloc unlock list.\n")); |
951 | 0 | TALLOC_FREE(l_ctx); |
952 | 0 | return False; |
953 | 0 | } |
954 | | |
955 | | /* |
956 | | * Create the initial list entry containing the |
957 | | * lock we want to add. |
958 | | */ |
959 | | |
960 | 0 | ZERO_STRUCTP(ll); |
961 | 0 | ll->start = offset; |
962 | 0 | ll->size = count; |
963 | |
|
964 | 0 | DLIST_ADD(llist, ll); |
965 | | |
966 | | /* |
967 | | * The following call calculates if there are any |
968 | | * overlapping locks held by this process on |
969 | | * fd's open on the same file and splits this list |
970 | | * into a list of lock ranges that do not overlap with existing |
971 | | * POSIX locks. |
972 | | */ |
973 | |
|
974 | 0 | llist = posix_lock_list(l_ctx, |
975 | 0 | llist, |
976 | 0 | lock_ctx, /* Lock context llist belongs to. */ |
977 | 0 | plocks, |
978 | 0 | num_locks); |
979 | | |
980 | | /* |
981 | | * Add the POSIX locks on the list of ranges returned. |
982 | | * As the lock is supposed to be added atomically, we need to |
983 | | * back out all the locks if any one of these calls fail. |
984 | | */ |
985 | |
|
986 | 0 | for (lock_count = 0, ll = llist; ll; ll = ll->next, lock_count++) { |
987 | 0 | offset = ll->start; |
988 | 0 | count = ll->size; |
989 | |
|
990 | 0 | DEBUG(5, ("set_posix_lock_windows_flavour: Real lock: " |
991 | 0 | "Type = %s: offset = %ju, count = %ju\n", |
992 | 0 | posix_lock_type_name(posix_lock_type), |
993 | 0 | (uintmax_t)offset, (uintmax_t)count )); |
994 | |
|
995 | 0 | if (!posix_fcntl_lock(fsp,F_SETLK,offset,count,posix_lock_type)) { |
996 | 0 | *errno_ret = errno; |
997 | 0 | DEBUG(5, ("set_posix_lock_windows_flavour: Lock " |
998 | 0 | "fail !: Type = %s: offset = %ju, " |
999 | 0 | "count = %ju. Errno = %s\n", |
1000 | 0 | posix_lock_type_name(posix_lock_type), |
1001 | 0 | (uintmax_t)offset, (uintmax_t)count, |
1002 | 0 | strerror(errno) )); |
1003 | 0 | ret = False; |
1004 | 0 | break; |
1005 | 0 | } |
1006 | 0 | } |
1007 | |
|
1008 | 0 | if (!ret) { |
1009 | | |
1010 | | /* |
1011 | | * Back out all the POSIX locks we have on fail. |
1012 | | */ |
1013 | |
|
1014 | 0 | for (ll = llist; lock_count; ll = ll->next, lock_count--) { |
1015 | 0 | offset = ll->start; |
1016 | 0 | count = ll->size; |
1017 | |
|
1018 | 0 | DEBUG(5, ("set_posix_lock_windows_flavour: Backing " |
1019 | 0 | "out locks: Type = %s: offset = %ju, " |
1020 | 0 | "count = %ju\n", |
1021 | 0 | posix_lock_type_name(posix_lock_type), |
1022 | 0 | (uintmax_t)offset, (uintmax_t)count )); |
1023 | |
|
1024 | 0 | posix_fcntl_lock(fsp,F_SETLK,offset,count,F_UNLCK); |
1025 | 0 | } |
1026 | 0 | } else { |
1027 | | /* Remember the number of locks we have on this dev/ino pair. */ |
1028 | 0 | increment_lock_ref_count(fsp); |
1029 | 0 | } |
1030 | |
|
1031 | 0 | TALLOC_FREE(l_ctx); |
1032 | 0 | return ret; |
1033 | 0 | } |
1034 | | |
1035 | | /**************************************************************************** |
1036 | | POSIX function to release a lock. Returns True if the |
1037 | | lock could be released, False if not. |
1038 | | ****************************************************************************/ |
1039 | | |
1040 | | bool release_posix_lock_windows_flavour(files_struct *fsp, |
1041 | | uint64_t u_offset, |
1042 | | uint64_t u_count, |
1043 | | enum brl_type deleted_lock_type, |
1044 | | const struct lock_context *lock_ctx, |
1045 | | const struct lock_struct *plocks, |
1046 | | int num_locks) |
1047 | 0 | { |
1048 | 0 | off_t offset; |
1049 | 0 | off_t count; |
1050 | 0 | bool ret = True; |
1051 | 0 | TALLOC_CTX *ul_ctx = NULL; |
1052 | 0 | struct lock_list *ulist = NULL; |
1053 | 0 | struct lock_list *ul = NULL; |
1054 | |
|
1055 | 0 | DBG_INFO("File %s, offset = %" PRIu64 ", " |
1056 | 0 | "count = %" PRIu64 "\n", |
1057 | 0 | fsp_str_dbg(fsp), |
1058 | 0 | u_offset, |
1059 | 0 | u_count); |
1060 | | |
1061 | | /* Remember the number of locks we have on this dev/ino pair. */ |
1062 | 0 | decrement_lock_ref_count(fsp); |
1063 | | |
1064 | | /* |
1065 | | * If the requested lock won't fit in the POSIX range, we will |
1066 | | * pretend it was successful. |
1067 | | */ |
1068 | |
|
1069 | 0 | if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) { |
1070 | 0 | return True; |
1071 | 0 | } |
1072 | | |
1073 | 0 | if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) { |
1074 | 0 | DBG_ERR("unable to init talloc context.\n"); |
1075 | 0 | return False; |
1076 | 0 | } |
1077 | | |
1078 | 0 | if ((ul = talloc(ul_ctx, struct lock_list)) == NULL) { |
1079 | 0 | DBG_ERR("unable to talloc unlock list.\n"); |
1080 | 0 | TALLOC_FREE(ul_ctx); |
1081 | 0 | return False; |
1082 | 0 | } |
1083 | | |
1084 | | /* |
1085 | | * Create the initial list entry containing the |
1086 | | * lock we want to remove. |
1087 | | */ |
1088 | | |
1089 | 0 | ZERO_STRUCTP(ul); |
1090 | 0 | ul->start = offset; |
1091 | 0 | ul->size = count; |
1092 | |
|
1093 | 0 | DLIST_ADD(ulist, ul); |
1094 | | |
1095 | | /* |
1096 | | * The following call calculates if there are any |
1097 | | * overlapping locks held by this process on |
1098 | | * fd's open on the same file and creates a |
1099 | | * list of unlock ranges that will allow |
1100 | | * POSIX lock ranges to remain on the file whilst the |
1101 | | * unlocks are performed. |
1102 | | */ |
1103 | |
|
1104 | 0 | ulist = posix_lock_list(ul_ctx, |
1105 | 0 | ulist, |
1106 | 0 | lock_ctx, /* Lock context ulist belongs to. */ |
1107 | 0 | plocks, |
1108 | 0 | num_locks); |
1109 | | |
1110 | | /* |
1111 | | * If there were any overlapped entries (list is > 1 or size or start have changed), |
1112 | | * and the lock_type we just deleted from |
1113 | | * the upper layer tdb was a write lock, then before doing the unlock we need to downgrade |
1114 | | * the POSIX lock to a read lock. This allows any overlapping read locks |
1115 | | * to be atomically maintained. |
1116 | | */ |
1117 | |
|
1118 | 0 | if (deleted_lock_type == WRITE_LOCK && |
1119 | 0 | (!ulist || ulist->next != NULL || ulist->start != offset || ulist->size != count)) { |
1120 | |
|
1121 | 0 | DBG_INFO("downgrading lock to READ: offset = %" PRIu64 |
1122 | 0 | ", count = %" PRIu64 "\n", |
1123 | 0 | offset, |
1124 | 0 | count); |
1125 | |
|
1126 | 0 | if (!posix_fcntl_lock(fsp,F_SETLK,offset,count,F_RDLCK)) { |
1127 | 0 | DBG_ERR("downgrade of lock failed with error %s !\n", |
1128 | 0 | strerror(errno)); |
1129 | 0 | TALLOC_FREE(ul_ctx); |
1130 | 0 | return False; |
1131 | 0 | } |
1132 | 0 | } |
1133 | | |
1134 | | /* |
1135 | | * Release the POSIX locks on the list of ranges returned. |
1136 | | */ |
1137 | | |
1138 | 0 | for(; ulist; ulist = ulist->next) { |
1139 | 0 | offset = ulist->start; |
1140 | 0 | count = ulist->size; |
1141 | |
|
1142 | 0 | DBG_INFO("Real unlock: offset = %" PRIu64 ", count = %" PRIu64 |
1143 | 0 | "\n", |
1144 | 0 | offset, |
1145 | 0 | count); |
1146 | |
|
1147 | 0 | if (!posix_fcntl_lock(fsp,F_SETLK,offset,count,F_UNLCK)) { |
1148 | 0 | ret = False; |
1149 | 0 | } |
1150 | 0 | } |
1151 | |
|
1152 | 0 | TALLOC_FREE(ul_ctx); |
1153 | 0 | return ret; |
1154 | 0 | } |
1155 | | |
1156 | | /**************************************************************************** |
1157 | | Next - the functions that deal with mapping CIFS POSIX locks onto |
1158 | | the underlying system POSIX locks. |
1159 | | ****************************************************************************/ |
1160 | | |
1161 | | /**************************************************************************** |
1162 | | We only increment the lock ref count when we see a POSIX lock on a context |
1163 | | that doesn't already have them. |
1164 | | ****************************************************************************/ |
1165 | | |
1166 | | static void increment_posix_lock_count(const files_struct *fsp, |
1167 | | uint64_t smblctx) |
1168 | 0 | { |
1169 | 0 | NTSTATUS status; |
1170 | 0 | TDB_DATA ctx_key; |
1171 | 0 | TDB_DATA val = { 0 }; |
1172 | |
|
1173 | 0 | ctx_key.dptr = (uint8_t *)&smblctx; |
1174 | 0 | ctx_key.dsize = sizeof(smblctx); |
1175 | | |
1176 | | /* |
1177 | | * Don't increment if we already have any POSIX flavor |
1178 | | * locks on this context. |
1179 | | */ |
1180 | 0 | if (dbwrap_exists(posix_pending_close_db, ctx_key)) { |
1181 | 0 | return; |
1182 | 0 | } |
1183 | | |
1184 | | /* Remember that we have POSIX flavor locks on this context. */ |
1185 | 0 | status = dbwrap_store(posix_pending_close_db, ctx_key, val, 0); |
1186 | 0 | SMB_ASSERT(NT_STATUS_IS_OK(status)); |
1187 | | |
1188 | 0 | increment_lock_ref_count(fsp); |
1189 | |
|
1190 | 0 | DEBUG(10,("posix_locks set for file %s\n", |
1191 | 0 | fsp_str_dbg(fsp))); |
1192 | 0 | } |
1193 | | |
1194 | | static void decrement_posix_lock_count(const files_struct *fsp, uint64_t smblctx) |
1195 | 0 | { |
1196 | 0 | NTSTATUS status; |
1197 | 0 | TDB_DATA ctx_key; |
1198 | |
|
1199 | 0 | ctx_key.dptr = (uint8_t *)&smblctx; |
1200 | 0 | ctx_key.dsize = sizeof(smblctx); |
1201 | |
|
1202 | 0 | status = dbwrap_delete(posix_pending_close_db, ctx_key); |
1203 | 0 | SMB_ASSERT(NT_STATUS_IS_OK(status)); |
1204 | | |
1205 | 0 | decrement_lock_ref_count(fsp); |
1206 | |
|
1207 | 0 | DEBUG(10,("posix_locks deleted for file %s\n", |
1208 | 0 | fsp_str_dbg(fsp))); |
1209 | 0 | } |
1210 | | |
1211 | | /**************************************************************************** |
1212 | | Return true if any locks exist on the given lock context. |
1213 | | ****************************************************************************/ |
1214 | | |
1215 | | static bool locks_exist_on_context(const struct lock_struct *plocks, |
1216 | | int num_locks, |
1217 | | const struct lock_context *lock_ctx) |
1218 | 0 | { |
1219 | 0 | int i; |
1220 | |
|
1221 | 0 | for (i=0; i < num_locks; i++) { |
1222 | 0 | const struct lock_struct *lock = &plocks[i]; |
1223 | | |
1224 | | /* Ignore all but read/write locks. */ |
1225 | 0 | if (lock->lock_type != READ_LOCK && lock->lock_type != WRITE_LOCK) { |
1226 | 0 | continue; |
1227 | 0 | } |
1228 | | |
1229 | | /* Ignore locks not owned by this process. */ |
1230 | 0 | if (!server_id_equal(&lock->context.pid, &lock_ctx->pid)) { |
1231 | 0 | continue; |
1232 | 0 | } |
1233 | | |
1234 | 0 | if (lock_ctx->smblctx == lock->context.smblctx) { |
1235 | 0 | return true; |
1236 | 0 | } |
1237 | 0 | } |
1238 | 0 | return false; |
1239 | 0 | } |
1240 | | |
1241 | | /**************************************************************************** |
1242 | | POSIX function to acquire a lock. Returns True if the |
1243 | | lock could be granted, False if not. |
1244 | | As POSIX locks don't stack or conflict (they just overwrite) |
1245 | | we can map the requested lock directly onto a system one. We |
1246 | | know it doesn't conflict with locks on other contexts as the |
1247 | | upper layer would have refused it. |
1248 | | ****************************************************************************/ |
1249 | | |
1250 | | bool set_posix_lock_posix_flavour(files_struct *fsp, |
1251 | | uint64_t u_offset, |
1252 | | uint64_t u_count, |
1253 | | enum brl_type lock_type, |
1254 | | const struct lock_context *lock_ctx, |
1255 | | int *errno_ret) |
1256 | 0 | { |
1257 | 0 | off_t offset; |
1258 | 0 | off_t count; |
1259 | 0 | int posix_lock_type = map_posix_lock_type(fsp,lock_type); |
1260 | |
|
1261 | 0 | DEBUG(5,("set_posix_lock_posix_flavour: File %s, offset = %ju, count " |
1262 | 0 | "= %ju, type = %s\n", fsp_str_dbg(fsp), |
1263 | 0 | (uintmax_t)u_offset, (uintmax_t)u_count, |
1264 | 0 | posix_lock_type_name(lock_type))); |
1265 | | |
1266 | | /* |
1267 | | * If the requested lock won't fit in the POSIX range, we will |
1268 | | * pretend it was successful. |
1269 | | */ |
1270 | |
|
1271 | 0 | if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) { |
1272 | 0 | increment_posix_lock_count(fsp, lock_ctx->smblctx); |
1273 | 0 | return True; |
1274 | 0 | } |
1275 | | |
1276 | 0 | if (!posix_fcntl_lock(fsp,F_SETLK,offset,count,posix_lock_type)) { |
1277 | 0 | *errno_ret = errno; |
1278 | 0 | DEBUG(5,("set_posix_lock_posix_flavour: Lock fail !: Type = %s: offset = %ju, count = %ju. Errno = %s\n", |
1279 | 0 | posix_lock_type_name(posix_lock_type), (intmax_t)offset, (intmax_t)count, strerror(errno) )); |
1280 | 0 | return False; |
1281 | 0 | } |
1282 | 0 | increment_posix_lock_count(fsp, lock_ctx->smblctx); |
1283 | 0 | return True; |
1284 | 0 | } |
1285 | | |
1286 | | /**************************************************************************** |
1287 | | POSIX function to release a lock. Returns True if the |
1288 | | lock could be released, False if not. |
1289 | | We are given a complete lock state from the upper layer which is what the lock |
1290 | | state should be after the unlock has already been done, so what |
1291 | | we do is punch out holes in the unlock range where locks owned by this process |
1292 | | have a different lock context. |
1293 | | ****************************************************************************/ |
1294 | | |
1295 | | bool release_posix_lock_posix_flavour(files_struct *fsp, |
1296 | | uint64_t u_offset, |
1297 | | uint64_t u_count, |
1298 | | const struct lock_context *lock_ctx, |
1299 | | const struct lock_struct *plocks, |
1300 | | int num_locks) |
1301 | 0 | { |
1302 | 0 | bool ret = True; |
1303 | 0 | off_t offset; |
1304 | 0 | off_t count; |
1305 | 0 | TALLOC_CTX *ul_ctx = NULL; |
1306 | 0 | struct lock_list *ulist = NULL; |
1307 | 0 | struct lock_list *ul = NULL; |
1308 | |
|
1309 | 0 | DEBUG(5, ("release_posix_lock_posix_flavour: File %s, offset = %ju, " |
1310 | 0 | "count = %ju\n", fsp_str_dbg(fsp), |
1311 | 0 | (uintmax_t)u_offset, (uintmax_t)u_count)); |
1312 | | |
1313 | | /* |
1314 | | * If the requested lock won't fit in the POSIX range, we will |
1315 | | * pretend it was successful. |
1316 | | */ |
1317 | |
|
1318 | 0 | if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) { |
1319 | 0 | if (!locks_exist_on_context(plocks, num_locks, lock_ctx)) { |
1320 | 0 | decrement_posix_lock_count(fsp, lock_ctx->smblctx); |
1321 | 0 | } |
1322 | 0 | return True; |
1323 | 0 | } |
1324 | | |
1325 | 0 | if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) { |
1326 | 0 | DEBUG(0,("release_posix_lock_windows_flavour: unable to init talloc context.\n")); |
1327 | 0 | return False; |
1328 | 0 | } |
1329 | | |
1330 | 0 | if ((ul = talloc(ul_ctx, struct lock_list)) == NULL) { |
1331 | 0 | DEBUG(0,("release_posix_lock_windows_flavour: unable to talloc unlock list.\n")); |
1332 | 0 | TALLOC_FREE(ul_ctx); |
1333 | 0 | return False; |
1334 | 0 | } |
1335 | | |
1336 | | /* |
1337 | | * Create the initial list entry containing the |
1338 | | * lock we want to remove. |
1339 | | */ |
1340 | | |
1341 | 0 | ZERO_STRUCTP(ul); |
1342 | 0 | ul->start = offset; |
1343 | 0 | ul->size = count; |
1344 | |
|
1345 | 0 | DLIST_ADD(ulist, ul); |
1346 | | |
1347 | | /* |
1348 | | * Walk the given array creating a linked list |
1349 | | * of unlock requests. |
1350 | | */ |
1351 | |
|
1352 | 0 | ulist = posix_lock_list(ul_ctx, |
1353 | 0 | ulist, |
1354 | 0 | lock_ctx, /* Lock context ulist belongs to. */ |
1355 | 0 | plocks, |
1356 | 0 | num_locks); |
1357 | | |
1358 | | /* |
1359 | | * Release the POSIX locks on the list of ranges returned. |
1360 | | */ |
1361 | |
|
1362 | 0 | for(; ulist; ulist = ulist->next) { |
1363 | 0 | offset = ulist->start; |
1364 | 0 | count = ulist->size; |
1365 | |
|
1366 | 0 | DEBUG(5, ("release_posix_lock_posix_flavour: Real unlock: " |
1367 | 0 | "offset = %ju, count = %ju\n", |
1368 | 0 | (uintmax_t)offset, (uintmax_t)count )); |
1369 | |
|
1370 | 0 | if (!posix_fcntl_lock(fsp,F_SETLK,offset,count,F_UNLCK)) { |
1371 | 0 | ret = False; |
1372 | 0 | } |
1373 | 0 | } |
1374 | |
|
1375 | 0 | if (!locks_exist_on_context(plocks, num_locks, lock_ctx)) { |
1376 | 0 | decrement_posix_lock_count(fsp, lock_ctx->smblctx); |
1377 | 0 | } |
1378 | | TALLOC_FREE(ul_ctx); |
1379 | 0 | return ret; |
1380 | 0 | } |