source: branches/samba-3.2.x/source/locking/posix.c@ 272

Last change on this file since 272 was 136, checked in by Paul Smedley, 17 years ago

Update trunk to 3.2.0rc1

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