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