2
Copyright (c) 2006, 2007, 2008 Gluster, Inc. <http://www.gluster.com>
3
This file is part of GlusterFS.
5
GlusterFS is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published
7
by the Free Software Foundation; either version 3 of the License,
8
or (at your option) any later version.
10
GlusterFS is distributed in the hope that it will be useful, but
11
WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see
17
<http://www.gnu.org/licenses/>.
25
#include "glusterfs.h"
30
#include "common-utils.h"
37
__delete_inode_lock (pl_inode_lock_t *lock)
39
list_del (&lock->list);
43
__destroy_inode_lock (pl_inode_lock_t *lock)
48
/* Check if 2 inodelks are conflicting on type. Only 2 shared locks don't conflict */
50
inodelk_type_conflict (pl_inode_lock_t *l1, pl_inode_lock_t *l2)
52
if (l2->fl_type == F_WRLCK || l1->fl_type == F_WRLCK)
59
pl_print_inodelk (char *str, int size, int cmd, struct flock *flock, const char *domain)
62
char *type_str = NULL;
65
#if F_GETLK != F_GETLK64
72
#if F_SETLK != F_SETLK64
79
#if F_SETLKW != F_SETLKW64
91
switch (flock->l_type) {
102
type_str = "UNKNOWN";
106
snprintf (str, size, "lock=INODELK, cmd=%s, type=%s, "
107
"domain: %s, start=%llu, len=%llu, pid=%llu",
108
cmd_str, type_str, domain,
109
(unsigned long long) flock->l_start,
110
(unsigned long long) flock->l_len,
111
(unsigned long long) flock->l_pid);
114
/* Determine if the two inodelks overlap reach other's lock regions */
116
inodelk_overlap (pl_inode_lock_t *l1, pl_inode_lock_t *l2)
118
return ((l1->fl_end >= l2->fl_start) &&
119
(l2->fl_end >= l1->fl_start));
122
/* Returns true if the 2 inodelks have the same owner */
123
static int same_inodelk_owner (pl_inode_lock_t *l1, pl_inode_lock_t *l2)
125
return ((l1->owner == l2->owner) &&
126
(l1->transport == l2->transport));
129
/* Returns true if the 2 inodelks conflict with each other */
131
inodelk_conflict (pl_inode_lock_t *l1, pl_inode_lock_t *l2)
133
if (same_inodelk_owner (l1, l2))
136
if (!inodelk_overlap (l1, l2))
139
return (inodelk_type_conflict(l1, l2));
142
/* Determine if lock is grantable or not */
143
static pl_inode_lock_t *
144
__inodelk_grantable (pl_dom_list_t *dom, pl_inode_lock_t *lock)
146
pl_inode_lock_t *l = NULL;
147
pl_inode_lock_t *ret = NULL;
148
if (list_empty (&dom->inodelk_list))
150
list_for_each_entry (l, &dom->inodelk_list, list){
151
if (inodelk_conflict (lock, l)) {
160
static pl_inode_lock_t *
161
__blocked_lock_conflict (pl_dom_list_t *dom, pl_inode_lock_t *lock)
163
pl_inode_lock_t *l = NULL;
164
pl_inode_lock_t *ret = NULL;
166
if (list_empty (&dom->blocked_entrylks))
169
list_for_each_entry (l, &dom->blocked_inodelks, blocked_locks) {
170
if (inodelk_conflict (lock, l)) {
181
__owner_has_lock (pl_dom_list_t *dom, pl_inode_lock_t *newlock)
183
pl_inode_lock_t *lock = NULL;
185
list_for_each_entry (lock, &dom->entrylk_list, list) {
186
if (same_inodelk_owner (lock, newlock))
190
list_for_each_entry (lock, &dom->blocked_entrylks, blocked_locks) {
191
if (same_inodelk_owner (lock, newlock))
199
/* Determines if lock can be granted and adds the lock. If the lock
200
* is blocking, adds it to the blocked_inodelks list of the domain.
203
__lock_inodelk (xlator_t *this, pl_inode_t *pl_inode, pl_inode_lock_t *lock,
204
int can_block, pl_dom_list_t *dom)
206
pl_inode_lock_t *conf = NULL;
209
conf = __inodelk_grantable (dom, lock);
215
list_add_tail (&lock->blocked_locks, &dom->blocked_inodelks);
217
gf_log (this->name, GF_LOG_TRACE,
218
"%s (pid=%d) lk-owner:%"PRIu64" %"PRId64" - %"PRId64" => Blocked",
219
lock->fl_type == F_UNLCK ? "Unlock" : "Lock",
222
lock->user_flock.l_start,
223
lock->user_flock.l_len);
229
if (__blocked_lock_conflict (dom, lock) && !(__owner_has_lock (dom, lock))) {
234
list_add_tail (&lock->blocked_locks, &dom->blocked_inodelks);
236
gf_log (this->name, GF_LOG_TRACE,
237
"Lock is grantable, but blocking to prevent starvation");
238
gf_log (this->name, GF_LOG_TRACE,
239
"%s (pid=%d) (lk-owner=%"PRIu64") %"PRId64" - %"PRId64" => Blocked",
240
lock->fl_type == F_UNLCK ? "Unlock" : "Lock",
243
lock->user_flock.l_start,
244
lock->user_flock.l_len);
249
list_add (&lock->list, &dom->inodelk_list);
257
/* Return true if the two inodelks have exactly same lock boundaries */
259
inodelks_equal (pl_inode_lock_t *l1, pl_inode_lock_t *l2)
261
if ((l1->fl_start == l2->fl_start) &&
262
(l1->fl_end == l2->fl_end))
269
static pl_inode_lock_t *
270
find_matching_inodelk (pl_inode_lock_t *lock, pl_dom_list_t *dom)
272
pl_inode_lock_t *l = NULL;
273
list_for_each_entry (l, &dom->inodelk_list, list) {
274
if (inodelks_equal (l, lock))
280
/* Set F_UNLCK removes a lock which has the exact same lock boundaries
281
* as the UNLCK lock specifies. If such a lock is not found, returns invalid
283
static pl_inode_lock_t *
284
__inode_unlock_lock (xlator_t *this, pl_inode_lock_t *lock, pl_dom_list_t *dom)
287
pl_inode_lock_t *conf = NULL;
289
conf = find_matching_inodelk (lock, dom);
291
gf_log (this->name, GF_LOG_DEBUG,
292
" Matching lock not found for unlock");
295
__delete_inode_lock (conf);
296
gf_log (this->name, GF_LOG_DEBUG,
297
" Matching lock found for unlock");
298
__destroy_inode_lock (lock);
307
__grant_blocked_inode_locks (xlator_t *this, pl_inode_t *pl_inode,
308
struct list_head *granted, pl_dom_list_t *dom)
311
pl_inode_lock_t *bl = NULL;
312
pl_inode_lock_t *tmp = NULL;
314
struct list_head blocked_list;
316
INIT_LIST_HEAD (&blocked_list);
317
list_splice_init (&dom->blocked_inodelks, &blocked_list);
319
list_for_each_entry_safe (bl, tmp, &blocked_list, blocked_locks) {
321
list_del_init (&bl->blocked_locks);
323
bl_ret = __lock_inodelk (this, pl_inode, bl, 1, dom);
326
list_add (&bl->blocked_locks, granted);
332
/* Grant all inodelks blocked on a lock */
334
grant_blocked_inode_locks (xlator_t *this, pl_inode_t *pl_inode, pl_dom_list_t *dom)
336
struct list_head granted;
337
pl_inode_lock_t *lock;
338
pl_inode_lock_t *tmp;
340
INIT_LIST_HEAD (&granted);
342
if (list_empty (&dom->blocked_inodelks)) {
343
gf_log (this->name, GF_LOG_TRACE,
344
"No blocked locks to be granted for domain: %s", dom->domain);
347
pthread_mutex_lock (&pl_inode->mutex);
349
__grant_blocked_inode_locks (this, pl_inode, &granted, dom);
351
pthread_mutex_unlock (&pl_inode->mutex);
353
list_for_each_entry_safe (lock, tmp, &granted, blocked_locks) {
354
gf_log (this->name, GF_LOG_TRACE,
355
"%s (pid=%d) (lk-owner=%"PRIu64") %"PRId64" - %"PRId64" => Granted",
356
lock->fl_type == F_UNLCK ? "Unlock" : "Lock",
359
lock->user_flock.l_start,
360
lock->user_flock.l_len);
362
pl_trace_out (this, lock->frame, NULL, NULL, F_SETLKW,
363
&lock->user_flock, 0, 0, lock->volume);
365
STACK_UNWIND_STRICT (inodelk, lock->frame, 0, 0);
370
/* Release all inodelks from this transport */
372
release_inode_locks_of_transport (xlator_t *this, pl_dom_list_t *dom,
373
inode_t *inode, transport_t *trans)
375
pl_inode_lock_t *tmp = NULL;
376
pl_inode_lock_t *l = NULL;
378
pl_inode_t * pinode = NULL;
380
struct list_head granted;
381
struct list_head released;
385
INIT_LIST_HEAD (&granted);
386
INIT_LIST_HEAD (&released);
388
pinode = pl_inode_get (this, inode);
390
pthread_mutex_lock (&pinode->mutex);
393
list_for_each_entry_safe (l, tmp, &dom->blocked_inodelks, blocked_locks) {
394
if (l->transport != trans)
397
list_del_init (&l->blocked_locks);
399
if (inode_path (inode, NULL, &path) < 0) {
400
gf_log (this->name, GF_LOG_TRACE,
401
"inode_path failed");
405
gf_log (this->name, GF_LOG_TRACE,
406
"releasing lock on %s held by "
407
"{transport=%p, pid=%"PRId64" lk-owner=%"PRIu64"}",
409
(uint64_t) l->client_pid,
412
list_add (&l->blocked_locks, &released);
416
list_for_each_entry_safe (l, tmp, &dom->inodelk_list, list) {
417
if (l->transport != trans)
420
__delete_inode_lock (l);
421
__destroy_inode_lock (l);
424
if (inode_path (inode, NULL, &path) < 0) {
425
gf_log (this->name, GF_LOG_TRACE,
426
"inode_path failed");
430
gf_log (this->name, GF_LOG_TRACE,
431
"releasing lock on %s held by "
432
"{transport=%p, pid=%"PRId64" lk-owner=%"PRIu64"}",
434
(uint64_t) l->client_pid,
444
pthread_mutex_unlock (&pinode->mutex);
446
list_for_each_entry_safe (l, tmp, &released, blocked_locks) {
447
list_del_init (&l->blocked_locks);
449
STACK_UNWIND_STRICT (inodelk, l->frame, -1, EAGAIN);
453
grant_blocked_inode_locks (this, pinode, dom);
459
pl_inode_setlk (xlator_t *this, pl_inode_t *pl_inode, pl_inode_lock_t *lock,
460
int can_block, pl_dom_list_t *dom)
463
pl_inode_lock_t *retlock = NULL;
465
pthread_mutex_lock (&pl_inode->mutex);
467
if (lock->fl_type != F_UNLCK) {
468
ret = __lock_inodelk (this, pl_inode, lock, can_block, dom);
470
gf_log (this->name, GF_LOG_TRACE,
471
"%s (pid=%d) (lk-owner=%"PRIu64") %"PRId64" - %"PRId64" => OK",
472
lock->fl_type == F_UNLCK ? "Unlock" : "Lock",
479
gf_log (this->name, GF_LOG_TRACE,
480
"%s (pid=%d) (lk-owner=%"PRIu64") %"PRId64" - %"PRId64" => NOK",
481
lock->fl_type == F_UNLCK ? "Unlock" : "Lock",
484
lock->user_flock.l_start,
485
lock->user_flock.l_len);
491
retlock = __inode_unlock_lock (this, lock, dom);
493
gf_log (this->name, GF_LOG_DEBUG,
494
"Bad Unlock issued on Inode lock");
498
__destroy_inode_lock (retlock);
505
pthread_mutex_unlock (&pl_inode->mutex);
506
grant_blocked_inode_locks (this, pl_inode, dom);
510
/* Create a new inode_lock_t */
512
new_inode_lock (struct flock *flock, transport_t *transport, pid_t client_pid,
513
uint64_t owner, const char *volume)
516
pl_inode_lock_t *lock = NULL;
518
lock = CALLOC (1, sizeof (*lock));
523
lock->fl_start = flock->l_start;
524
lock->fl_type = flock->l_type;
526
if (flock->l_len == 0)
527
lock->fl_end = LLONG_MAX;
529
lock->fl_end = flock->l_start + flock->l_len - 1;
531
lock->transport = transport;
532
lock->client_pid = client_pid;
534
lock->volume = volume;
536
INIT_LIST_HEAD (&lock->list);
537
INIT_LIST_HEAD (&lock->blocked_locks);
542
/* Common inodelk code called from pl_inodelk and pl_finodelk */
544
pl_common_inodelk (call_frame_t *frame, xlator_t *this,
545
const char *volume, inode_t *inode, int32_t cmd,
546
struct flock *flock, loc_t *loc, fd_t *fd)
549
int32_t op_errno = 0;
552
transport_t * transport = NULL;
553
pid_t client_pid = -1;
555
pl_inode_t * pinode = NULL;
556
pl_inode_lock_t * reqlock = NULL;
557
pl_dom_list_t * dom = NULL;
559
VALIDATE_OR_GOTO (frame, out);
560
VALIDATE_OR_GOTO (inode, unwind);
561
VALIDATE_OR_GOTO (flock, unwind);
563
if ((flock->l_start < 0) || (flock->l_len < 0)) {
568
pl_trace_in (this, frame, fd, loc, cmd, flock, volume);
570
transport = frame->root->trans;
571
client_pid = frame->root->pid;
572
owner = (uint64_t) (long)frame->root;
574
pinode = pl_inode_get (this, inode);
576
gf_log (this->name, GF_LOG_ERROR,
582
dom = get_domain (pinode, volume);
584
if (client_pid == 0) {
586
special case: this means release all locks
589
gf_log (this->name, GF_LOG_TRACE,
590
"Releasing all locks from transport %p", transport);
592
release_inode_locks_of_transport (this, dom, inode, transport);
596
reqlock = new_inode_lock (flock, transport, client_pid, owner, volume);
599
gf_log (this->name, GF_LOG_ERROR,
609
reqlock->frame = frame;
610
reqlock->this = this;
615
memcpy (&reqlock->user_flock, flock, sizeof (struct flock));
616
ret = pl_inode_setlk (this, pinode, reqlock,
621
pl_trace_block (this, frame, fd, loc,
625
gf_log (this->name, GF_LOG_TRACE, "returning EAGAIN");
627
__destroy_inode_lock (reqlock);
634
gf_log (this->name, GF_LOG_DEBUG,
635
"Lock command F_GETLK not supported for [f]inodelk "
644
if ((inode != NULL) && (flock !=NULL)) {
645
pl_update_refkeeper (this, inode);
646
pl_trace_out (this, frame, fd, loc, cmd, flock, op_ret, op_errno, volume);
649
STACK_UNWIND_STRICT (inodelk, frame, op_ret, op_errno);
655
pl_inodelk (call_frame_t *frame, xlator_t *this,
656
const char *volume, loc_t *loc, int32_t cmd, struct flock *flock)
659
pl_common_inodelk (frame, this, volume, loc->inode, cmd, flock, loc, NULL);
665
pl_finodelk (call_frame_t *frame, xlator_t *this,
666
const char *volume, fd_t *fd, int32_t cmd, struct flock *flock)
669
pl_common_inodelk (frame, this, volume, fd->inode, cmd, flock, NULL, fd);
677
__get_inodelk_count (xlator_t *this, pl_inode_t *pl_inode)
680
pl_inode_lock_t *lock = NULL;
681
pl_dom_list_t *dom = NULL;
683
list_for_each_entry (dom, &pl_inode->dom_list, inode_list) {
684
list_for_each_entry (lock, &dom->inodelk_list, list) {
686
gf_log (this->name, GF_LOG_DEBUG,
688
" domain: %s %s (pid=%d) (lk-owner=%"PRIu64") %"PRId64" - %"PRId64" "
691
lock->fl_type == F_UNLCK ? "Unlock" : "Lock",
694
lock->user_flock.l_start,
695
lock->user_flock.l_len);
700
list_for_each_entry (lock, &dom->blocked_inodelks, blocked_locks) {
702
gf_log (this->name, GF_LOG_DEBUG,
704
" domain: %s %s (pid=%d) (lk-owner=%"PRIu64") %"PRId64" - %"PRId64" "
707
lock->fl_type == F_UNLCK ? "Unlock" : "Lock",
710
lock->user_flock.l_start,
711
lock->user_flock.l_len);
722
get_inodelk_count (xlator_t *this, inode_t *inode)
724
pl_inode_t *pl_inode = NULL;
725
uint64_t tmp_pl_inode = 0;
729
ret = inode_ctx_get (inode, this, &tmp_pl_inode);
734
pl_inode = (pl_inode_t *)(long) tmp_pl_inode;
736
pthread_mutex_lock (&pl_inode->mutex);
738
count = __get_inodelk_count (this, pl_inode);
740
pthread_mutex_unlock (&pl_inode->mutex);