diff options
Diffstat (limited to 'xlators/features/locks/src/common.c')
| -rw-r--r-- | xlators/features/locks/src/common.c | 634 |
1 files changed, 438 insertions, 196 deletions
diff --git a/xlators/features/locks/src/common.c b/xlators/features/locks/src/common.c index b34cd9781..b3309580d 100644 --- a/xlators/features/locks/src/common.c +++ b/xlators/features/locks/src/common.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2006, 2007, 2008 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <unistd.h> #include <fcntl.h> #include <limits.h> @@ -42,24 +32,23 @@ static int __is_lock_grantable (pl_inode_t *pl_inode, posix_lock_t *lock); static void __insert_and_merge (pl_inode_t *pl_inode, posix_lock_t *lock); +static int +pl_send_prelock_unlock (xlator_t *this, pl_inode_t *pl_inode, + posix_lock_t *old_lock); static pl_dom_list_t * -allocate_domain (const char *volume) +__allocate_domain (const char *volume) { pl_dom_list_t *dom = NULL; dom = GF_CALLOC (1, sizeof (*dom), gf_locks_mt_pl_dom_list_t); if (!dom) - return NULL; - + goto out; dom->domain = gf_strdup(volume); - if (!dom->domain) { - gf_log ("posix-locks", GF_LOG_TRACE, - "Out of Memory"); - return NULL; - } + if (!dom->domain) + goto out; gf_log ("posix-locks", GF_LOG_TRACE, "New domain allocated: %s", dom->domain); @@ -70,6 +59,12 @@ allocate_domain (const char *volume) INIT_LIST_HEAD (&dom->inodelk_list); INIT_LIST_HEAD (&dom->blocked_inodelks); +out: + if (dom && (NULL == dom->domain)) { + GF_FREE (dom); + dom = NULL; + } + return dom; } @@ -81,19 +76,28 @@ get_domain (pl_inode_t *pl_inode, const char *volume) { pl_dom_list_t *dom = NULL; - list_for_each_entry (dom, &pl_inode->dom_list, inode_list) { - if (strcmp (dom->domain, volume) == 0) - goto found; + GF_VALIDATE_OR_GOTO ("posix-locks", pl_inode, out); + GF_VALIDATE_OR_GOTO ("posix-locks", volume, out); + pthread_mutex_lock (&pl_inode->mutex); + { + list_for_each_entry (dom, &pl_inode->dom_list, inode_list) { + if (strcmp (dom->domain, volume) == 0) + goto unlock; + } + dom = __allocate_domain (volume); + if (dom) + list_add (&dom->inode_list, &pl_inode->dom_list); } - - dom = allocate_domain(volume); - - if (dom) - list_add (&dom->inode_list, &pl_inode->dom_list); -found: - +unlock: + pthread_mutex_unlock (&pl_inode->mutex); + if (dom) { + gf_log ("posix-locks", GF_LOG_TRACE, "Domain %s found", volume); + } else { + gf_log ("posix-locks", GF_LOG_TRACE, "Domain %s not found", volume); + } +out: return dom; } @@ -103,6 +107,12 @@ fd_to_fdnum (fd_t *fd) return ((unsigned long) fd); } +fd_t * +fd_from_fdnum (posix_lock_t *lock) +{ + return ((fd_t *) lock->fd_num); +} + int __pl_inode_is_empty (pl_inode_t *pl_inode) { @@ -126,10 +136,10 @@ __pl_inode_is_empty (pl_inode_t *pl_inode) void pl_print_locker (char *str, int size, xlator_t *this, call_frame_t *frame) { - snprintf (str, size, "Pid=%llu, lk-owner=%llu, Transport=%p, Frame=%llu", + snprintf (str, size, "Pid=%llu, lk-owner=%s, Client=%p, Frame=%llu", (unsigned long long) frame->root->pid, - (unsigned long long) frame->root->lk_owner, - (void *)frame->root->trans, + lkowner_utoa (&frame->root->lk_owner), + frame->root->client, (unsigned long long) frame->root->unique); } @@ -159,18 +169,17 @@ pl_print_lockee (char *str, int size, fd_t *fd, loc_t *loc) ipath = NULL; } - snprintf (str, size, "ino=%llu, fd=%p, path=%s", - (unsigned long long) inode->ino, fd, + snprintf (str, size, "gfid=%s, fd=%p, path=%s", + uuid_utoa (inode->gfid), fd, ipath ? ipath : "<nul>"); - if (ipath) - GF_FREE (ipath); + GF_FREE (ipath); } void pl_print_lock (char *str, int size, int cmd, - struct flock *flock, uint64_t owner) + struct gf_flock *flock, gf_lkowner_t *owner) { char *cmd_str = NULL; char *type_str = NULL; @@ -218,17 +227,17 @@ pl_print_lock (char *str, int size, int cmd, } snprintf (str, size, "lock=FCNTL, cmd=%s, type=%s, " - "start=%llu, len=%llu, pid=%llu, lk-owner=%llu", + "start=%llu, len=%llu, pid=%llu, lk-owner=%s", cmd_str, type_str, (unsigned long long) flock->l_start, (unsigned long long) flock->l_len, (unsigned long long) flock->l_pid, - (unsigned long long) owner); + lkowner_utoa (owner)); } void pl_trace_in (xlator_t *this, call_frame_t *frame, fd_t *fd, loc_t *loc, - int cmd, struct flock *flock, const char *domain) + int cmd, struct gf_flock *flock, const char *domain) { posix_locks_private_t *priv = NULL; char pl_locker[256]; @@ -245,9 +254,9 @@ pl_trace_in (xlator_t *this, call_frame_t *frame, fd_t *fd, loc_t *loc, if (domain) pl_print_inodelk (pl_lock, 256, cmd, flock, domain); else - pl_print_lock (pl_lock, 256, cmd, flock, frame->root->lk_owner); + pl_print_lock (pl_lock, 256, cmd, flock, &frame->root->lk_owner); - gf_log (this->name, GF_LOG_NORMAL, + gf_log (this->name, GF_LOG_INFO, "[REQUEST] Locker = {%s} Lockee = {%s} Lock = {%s}", pl_locker, pl_lockee, pl_lock); } @@ -276,7 +285,7 @@ pl_print_verdict (char *str, int size, int op_ret, int op_errno) void pl_trace_out (xlator_t *this, call_frame_t *frame, fd_t *fd, loc_t *loc, - int cmd, struct flock *flock, int op_ret, int op_errno, const char *domain) + int cmd, struct gf_flock *flock, int op_ret, int op_errno, const char *domain) { posix_locks_private_t *priv = NULL; @@ -295,11 +304,11 @@ pl_trace_out (xlator_t *this, call_frame_t *frame, fd_t *fd, loc_t *loc, if (domain) pl_print_inodelk (pl_lock, 256, cmd, flock, domain); else - pl_print_lock (pl_lock, 256, cmd, flock, frame->root->lk_owner); + pl_print_lock (pl_lock, 256, cmd, flock, &frame->root->lk_owner); pl_print_verdict (verdict, 32, op_ret, op_errno); - gf_log (this->name, GF_LOG_NORMAL, + gf_log (this->name, GF_LOG_INFO, "[%s] Locker = {%s} Lockee = {%s} Lock = {%s}", verdict, pl_locker, pl_lockee, pl_lock); } @@ -307,7 +316,7 @@ pl_trace_out (xlator_t *this, call_frame_t *frame, fd_t *fd, loc_t *loc, void pl_trace_block (xlator_t *this, call_frame_t *frame, fd_t *fd, loc_t *loc, - int cmd, struct flock *flock, const char *domain) + int cmd, struct gf_flock *flock, const char *domain) { posix_locks_private_t *priv = NULL; @@ -325,9 +334,9 @@ pl_trace_block (xlator_t *this, call_frame_t *frame, fd_t *fd, loc_t *loc, if (domain) pl_print_inodelk (pl_lock, 256, cmd, flock, domain); else - pl_print_lock (pl_lock, 256, cmd, flock, frame->root->lk_owner); + pl_print_lock (pl_lock, 256, cmd, flock, &frame->root->lk_owner); - gf_log (this->name, GF_LOG_NORMAL, + gf_log (this->name, GF_LOG_INFO, "[BLOCKED] Locker = {%s} Lockee = {%s} Lock = {%s}", pl_locker, pl_lockee, pl_lock); } @@ -354,7 +363,7 @@ pl_trace_flush (xlator_t *this, call_frame_t *frame, fd_t *fd) pl_print_locker (pl_locker, 256, this, frame); pl_print_lockee (pl_lockee, 256, fd, NULL); - gf_log (this->name, GF_LOG_NORMAL, + gf_log (this->name, GF_LOG_INFO, "[FLUSH] Locker = {%s} Lockee = {%s}", pl_locker, pl_lockee); } @@ -372,7 +381,7 @@ pl_trace_release (xlator_t *this, fd_t *fd) pl_print_lockee (pl_lockee, 256, fd, NULL); - gf_log (this->name, GF_LOG_NORMAL, + gf_log (this->name, GF_LOG_INFO, "[RELEASE] Lockee = {%s}", pl_lockee); } @@ -383,6 +392,7 @@ pl_update_refkeeper (xlator_t *this, inode_t *inode) pl_inode_t *pl_inode = NULL; int is_empty = 0; int need_unref = 0; + int need_ref = 0; pl_inode = pl_inode_get (this, inode); @@ -396,13 +406,17 @@ pl_update_refkeeper (xlator_t *this, inode_t *inode) } if (!is_empty && !pl_inode->refkeeper) { - pl_inode->refkeeper = inode_ref (inode); + need_ref = 1; + pl_inode->refkeeper = inode; } } pthread_mutex_unlock (&pl_inode->mutex); if (need_unref) inode_unref (inode); + + if (need_ref) + inode_ref (inode); } @@ -410,74 +424,78 @@ pl_inode_t * pl_inode_get (xlator_t *this, inode_t *inode) { uint64_t tmp_pl_inode = 0; - pl_inode_t *pl_inode = NULL; -// mode_t st_mode = 0; - int ret = 0; - - ret = inode_ctx_get (inode, this,&tmp_pl_inode); - if (ret == 0) { - pl_inode = (pl_inode_t *)(long)tmp_pl_inode; - goto out; - } - pl_inode = GF_CALLOC (1, sizeof (*pl_inode), - gf_locks_mt_pl_inode_t); - if (!pl_inode) { - gf_log (this->name, GF_LOG_ERROR, - "Out of memory."); - goto out; - } - - gf_log (this->name, GF_LOG_TRACE, - "Allocating new pl inode"); + pl_inode_t *pl_inode = NULL; + int ret = 0; -/* - st_mode = inode->st_mode; - if ((st_mode & S_ISGID) && !(st_mode & S_IXGRP)) - pl_inode->mandatory = 1; -*/ + LOCK (&inode->lock); + { + ret = __inode_ctx_get (inode, this, &tmp_pl_inode); + if (ret == 0) { + pl_inode = (pl_inode_t *)(long)tmp_pl_inode; + goto unlock; + } + pl_inode = GF_CALLOC (1, sizeof (*pl_inode), + gf_locks_mt_pl_inode_t); + if (!pl_inode) { + goto unlock; + } - pthread_mutex_init (&pl_inode->mutex, NULL); + gf_log (this->name, GF_LOG_TRACE, + "Allocating new pl inode"); - INIT_LIST_HEAD (&pl_inode->dom_list); - INIT_LIST_HEAD (&pl_inode->ext_list); - INIT_LIST_HEAD (&pl_inode->rw_list); + pthread_mutex_init (&pl_inode->mutex, NULL); - inode_ctx_put (inode, this, (uint64_t)(long)(pl_inode)); + INIT_LIST_HEAD (&pl_inode->dom_list); + INIT_LIST_HEAD (&pl_inode->ext_list); + INIT_LIST_HEAD (&pl_inode->rw_list); + INIT_LIST_HEAD (&pl_inode->reservelk_list); + INIT_LIST_HEAD (&pl_inode->blocked_reservelks); + INIT_LIST_HEAD (&pl_inode->blocked_calls); -out: - return pl_inode; + __inode_ctx_put (inode, this, (uint64_t)(long)(pl_inode)); + } +unlock: + UNLOCK (&inode->lock); + + return pl_inode; } /* Create a new posix_lock_t */ posix_lock_t * -new_posix_lock (struct flock *flock, void *transport, pid_t client_pid, - uint64_t owner, fd_t *fd) +new_posix_lock (struct gf_flock *flock, client_t *client, pid_t client_pid, + gf_lkowner_t *owner, fd_t *fd) { - posix_lock_t *lock = NULL; + posix_lock_t *lock = NULL; + + GF_VALIDATE_OR_GOTO ("posix-locks", flock, out); + GF_VALIDATE_OR_GOTO ("posix-locks", client, out); + GF_VALIDATE_OR_GOTO ("posix-locks", fd, out); - lock = GF_CALLOC (1, sizeof (posix_lock_t), + lock = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); - if (!lock) { - return NULL; - } + if (!lock) { + goto out; + } - lock->fl_start = flock->l_start; - lock->fl_type = flock->l_type; + lock->fl_start = flock->l_start; + lock->fl_type = flock->l_type; - if (flock->l_len == 0) - lock->fl_end = LLONG_MAX; - else - lock->fl_end = flock->l_start + flock->l_len - 1; + if (flock->l_len == 0) + lock->fl_end = LLONG_MAX; + else + lock->fl_end = flock->l_start + flock->l_len - 1; - lock->transport = transport; + lock->client = client; lock->fd_num = fd_to_fdnum (fd); - lock->client_pid = client_pid; - lock->owner = owner; + lock->fd = fd; + lock->client_pid = client_pid; + lock->owner = *owner; - INIT_LIST_HEAD (&lock->list); + INIT_LIST_HEAD (&lock->list); - return lock; +out: + return lock; } @@ -485,7 +503,7 @@ new_posix_lock (struct flock *flock, void *transport, pid_t client_pid, void __delete_lock (pl_inode_t *pl_inode, posix_lock_t *lock) { - list_del_init (&lock->list); + list_del_init (&lock->list); } @@ -493,32 +511,37 @@ __delete_lock (pl_inode_t *pl_inode, posix_lock_t *lock) void __destroy_lock (posix_lock_t *lock) { - GF_FREE (lock); + GF_FREE (lock); } -/* Convert a posix_lock to a struct flock */ +/* Convert a posix_lock to a struct gf_flock */ void -posix_lock_to_flock (posix_lock_t *lock, struct flock *flock) +posix_lock_to_flock (posix_lock_t *lock, struct gf_flock *flock) { - flock->l_pid = lock->client_pid; - flock->l_type = lock->fl_type; - flock->l_start = lock->fl_start; + flock->l_pid = lock->client_pid; + flock->l_type = lock->fl_type; + flock->l_start = lock->fl_start; + flock->l_owner = lock->owner; - if (lock->fl_end == LLONG_MAX) - flock->l_len = 0; - else - flock->l_len = lock->fl_end - lock->fl_start + 1; + if (lock->fl_end == LLONG_MAX) + flock->l_len = 0; + else + flock->l_len = lock->fl_end - lock->fl_start + 1; } - /* Insert the lock into the inode's lock list */ static void __insert_lock (pl_inode_t *pl_inode, posix_lock_t *lock) { - list_add_tail (&lock->list, &pl_inode->ext_list); + if (lock->blocked) + gettimeofday (&lock->blkd_time, NULL); + else + gettimeofday (&lock->granted_time, NULL); - return; + list_add_tail (&lock->list, &pl_inode->ext_list); + + return; } @@ -526,14 +549,14 @@ __insert_lock (pl_inode_t *pl_inode, posix_lock_t *lock) int locks_overlap (posix_lock_t *l1, posix_lock_t *l2) { - /* - Note: - FUSE always gives us absolute offsets, so no need to worry - about SEEK_CUR or SEEK_END - */ - - return ((l1->fl_end >= l2->fl_start) && - (l2->fl_end >= l1->fl_start)); + /* + Note: + FUSE always gives us absolute offsets, so no need to worry + about SEEK_CUR or SEEK_END + */ + + return ((l1->fl_end >= l2->fl_start) && + (l2->fl_end >= l1->fl_start)); } @@ -542,8 +565,8 @@ int same_owner (posix_lock_t *l1, posix_lock_t *l2) { - return ((l1->owner == l2->owner) && - (l1->transport == l2->transport)); + return (is_same_lkowner (&l1->owner, &l2->owner) && + (l1->client == l2->client)); } @@ -552,15 +575,15 @@ same_owner (posix_lock_t *l1, posix_lock_t *l2) void __delete_unlck_locks (pl_inode_t *pl_inode) { - posix_lock_t *l = NULL; - posix_lock_t *tmp = NULL; + posix_lock_t *l = NULL; + posix_lock_t *tmp = NULL; - list_for_each_entry_safe (l, tmp, &pl_inode->ext_list, list) { - if (l->fl_type == F_UNLCK) { - __delete_lock (pl_inode, l); - __destroy_lock (l); - } - } + list_for_each_entry_safe (l, tmp, &pl_inode->ext_list, list) { + if (l->fl_type == F_UNLCK) { + __delete_lock (pl_inode, l); + __destroy_lock (l); + } + } } @@ -568,22 +591,22 @@ __delete_unlck_locks (pl_inode_t *pl_inode) static posix_lock_t * add_locks (posix_lock_t *l1, posix_lock_t *l2) { - posix_lock_t *sum = NULL; + posix_lock_t *sum = NULL; - sum = GF_CALLOC (1, sizeof (posix_lock_t), + sum = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); - if (!sum) - return NULL; + if (!sum) + return NULL; - sum->fl_start = min (l1->fl_start, l2->fl_start); - sum->fl_end = max (l1->fl_end, l2->fl_end); + sum->fl_start = min (l1->fl_start, l2->fl_start); + sum->fl_end = max (l1->fl_end, l2->fl_end); - return sum; + return sum; } /* Subtract two locks */ struct _values { - posix_lock_t *locks[3]; + posix_lock_t *locks[3]; }; /* {big} must always be contained inside {small} */ @@ -591,89 +614,88 @@ static struct _values subtract_locks (posix_lock_t *big, posix_lock_t *small) { - struct _values v = { .locks = {0, 0, 0} }; + struct _values v = { .locks = {0, 0, 0} }; - if ((big->fl_start == small->fl_start) && - (big->fl_end == small->fl_end)) { - /* both edges coincide with big */ - v.locks[0] = GF_CALLOC (1, sizeof (posix_lock_t), + if ((big->fl_start == small->fl_start) && + (big->fl_end == small->fl_end)) { + /* both edges coincide with big */ + v.locks[0] = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); if (!v.locks[0]) goto out; - memcpy (v.locks[0], big, sizeof (posix_lock_t)); - v.locks[0]->fl_type = small->fl_type; + memcpy (v.locks[0], big, sizeof (posix_lock_t)); + v.locks[0]->fl_type = small->fl_type; goto done; - } + } - if ((small->fl_start > big->fl_start) && + if ((small->fl_start > big->fl_start) && (small->fl_end < big->fl_end)) { - /* both edges lie inside big */ - v.locks[0] = GF_CALLOC (1, sizeof (posix_lock_t), + /* both edges lie inside big */ + v.locks[0] = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); if (!v.locks[0]) goto out; - v.locks[1] = GF_CALLOC (1, sizeof (posix_lock_t), + v.locks[1] = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); if (!v.locks[1]) goto out; - v.locks[2] = GF_CALLOC (1, sizeof (posix_lock_t), + v.locks[2] = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); if (!v.locks[1]) goto out; - memcpy (v.locks[0], big, sizeof (posix_lock_t)); - v.locks[0]->fl_end = small->fl_start - 1; + memcpy (v.locks[0], big, sizeof (posix_lock_t)); + v.locks[0]->fl_end = small->fl_start - 1; - memcpy (v.locks[1], small, sizeof (posix_lock_t)); + memcpy (v.locks[1], small, sizeof (posix_lock_t)); - memcpy (v.locks[2], big, sizeof (posix_lock_t)); - v.locks[2]->fl_start = small->fl_end + 1; + memcpy (v.locks[2], big, sizeof (posix_lock_t)); + v.locks[2]->fl_start = small->fl_end + 1; goto done; - } + } - /* one edge coincides with big */ + /* one edge coincides with big */ if (small->fl_start == big->fl_start) { - v.locks[0] = GF_CALLOC (1, sizeof (posix_lock_t), + v.locks[0] = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); if (!v.locks[0]) goto out; - v.locks[1] = GF_CALLOC (1, sizeof (posix_lock_t), + v.locks[1] = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); if (!v.locks[1]) goto out; - memcpy (v.locks[0], big, sizeof (posix_lock_t)); - v.locks[0]->fl_start = small->fl_end + 1; + memcpy (v.locks[0], big, sizeof (posix_lock_t)); + v.locks[0]->fl_start = small->fl_end + 1; - memcpy (v.locks[1], small, sizeof (posix_lock_t)); + memcpy (v.locks[1], small, sizeof (posix_lock_t)); goto done; - } + } - if (small->fl_end == big->fl_end) { - v.locks[0] = GF_CALLOC (1, sizeof (posix_lock_t), + if (small->fl_end == big->fl_end) { + v.locks[0] = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); if (!v.locks[0]) goto out; - v.locks[1] = GF_CALLOC (1, sizeof (posix_lock_t), + v.locks[1] = GF_CALLOC (1, sizeof (posix_lock_t), gf_locks_mt_posix_lock_t); if (!v.locks[1]) goto out; - memcpy (v.locks[0], big, sizeof (posix_lock_t)); - v.locks[0]->fl_end = small->fl_start - 1; + memcpy (v.locks[0], big, sizeof (posix_lock_t)); + v.locks[0]->fl_end = small->fl_start - 1; - memcpy (v.locks[1], small, sizeof (posix_lock_t)); + memcpy (v.locks[1], small, sizeof (posix_lock_t)); goto done; - } + } - gf_log ("posix-locks", GF_LOG_ERROR, - "Unexpected case in subtract_locks. Please send " - "a bug report to gluster-devel@nongnu.org"); + GF_ASSERT (0); + gf_log ("posix-locks", GF_LOG_ERROR, "Unexpected case in subtract_locks"); out: if (v.locks[0]) { @@ -693,6 +715,36 @@ done: return v; } +static posix_lock_t * +first_conflicting_overlap (pl_inode_t *pl_inode, posix_lock_t *lock) +{ + posix_lock_t *l = NULL; + posix_lock_t *conf = NULL; + + pthread_mutex_lock (&pl_inode->mutex); + { + list_for_each_entry (l, &pl_inode->ext_list, list) { + if (l->blocked) + continue; + + if (locks_overlap (l, lock)) { + if (same_owner (l, lock)) + continue; + + if ((l->fl_type == F_WRLCK) || + (lock->fl_type == F_WRLCK)) { + conf = l; + goto unlock; + } + } + } + } +unlock: + pthread_mutex_unlock (&pl_inode->mutex); + + return conf; +} + /* Start searching from {begin}, and return the first lock that conflicts, NULL if no conflict @@ -751,6 +803,8 @@ __insert_and_merge (pl_inode_t *pl_inode, posix_lock_t *lock) struct _values v = { .locks = {0, 0, 0} }; list_for_each_entry_safe (conf, t, &pl_inode->ext_list, list) { + if (conf->blocked) + continue; if (!locks_overlap (conf, lock)) continue; @@ -759,7 +813,7 @@ __insert_and_merge (pl_inode_t *pl_inode, posix_lock_t *lock) sum = add_locks (lock, conf); sum->fl_type = lock->fl_type; - sum->transport = lock->transport; + sum->client = lock->client; sum->fd_num = lock->fd_num; sum->client_pid = lock->client_pid; sum->owner = lock->owner; @@ -768,6 +822,8 @@ __insert_and_merge (pl_inode_t *pl_inode, posix_lock_t *lock) __destroy_lock (conf); __destroy_lock (lock); + INIT_LIST_HEAD (&sum->list); + posix_lock_to_flock (sum, &sum->user_flock); __insert_and_merge (pl_inode, sum); return; @@ -775,7 +831,7 @@ __insert_and_merge (pl_inode_t *pl_inode, posix_lock_t *lock) sum = add_locks (lock, conf); sum->fl_type = conf->fl_type; - sum->transport = conf->transport; + sum->client = conf->client; sum->fd_num = conf->fd_num; sum->client_pid = conf->client_pid; sum->owner = conf->owner; @@ -795,6 +851,8 @@ __insert_and_merge (pl_inode_t *pl_inode, posix_lock_t *lock) continue; INIT_LIST_HEAD (&v.locks[i]->list); + posix_lock_to_flock (v.locks[i], + &v.locks[i]->user_flock); __insert_and_merge (pl_inode, v.locks[i]); } @@ -848,7 +906,7 @@ __grant_blocked_locks (xlator_t *this, pl_inode_t *pl_inode, struct list_head *g list_del_init (&l->list); if (__is_lock_grantable (pl_inode, l)) { - conf = GF_CALLOC (1, sizeof (*conf), + conf = GF_CALLOC (1, sizeof (*conf), gf_locks_mt_posix_lock_t); if (!conf) { @@ -863,10 +921,9 @@ __grant_blocked_locks (xlator_t *this, pl_inode_t *pl_inode, struct list_head *g posix_lock_to_flock (l, &conf->user_flock); gf_log (this->name, GF_LOG_TRACE, - "%s (pid=%d) lk-owner:%"PRIu64" %"PRId64" - %"PRId64" => Granted", + "%s (pid=%d) lk-owner:%s %"PRId64" - %"PRId64" => Granted", l->fl_type == F_UNLCK ? "Unlock" : "Lock", - l->client_pid, - l->owner, + l->client_pid, lkowner_utoa (&l->owner), l->user_flock.l_start, l->user_flock.l_len); @@ -902,7 +959,8 @@ grant_blocked_locks (xlator_t *this, pl_inode_t *pl_inode) pl_trace_out (this, lock->frame, NULL, NULL, F_SETLKW, &lock->user_flock, 0, 0, NULL); - STACK_UNWIND (lock->frame, 0, 0, &lock->user_flock); + STACK_UNWIND_STRICT (lk, lock->frame, 0, 0, + &lock->user_flock, NULL); GF_FREE (lock); } @@ -910,6 +968,52 @@ grant_blocked_locks (xlator_t *this, pl_inode_t *pl_inode) return; } +static int +pl_send_prelock_unlock (xlator_t *this, pl_inode_t *pl_inode, + posix_lock_t *old_lock) +{ + struct gf_flock flock = {0,}; + posix_lock_t *unlock_lock = NULL; + + struct list_head granted_list; + posix_lock_t *tmp = NULL; + posix_lock_t *lock = NULL; + + int ret = -1; + + INIT_LIST_HEAD (&granted_list); + + flock.l_type = F_UNLCK; + flock.l_whence = old_lock->user_flock.l_whence; + flock.l_start = old_lock->user_flock.l_start; + flock.l_len = old_lock->user_flock.l_len; + + + unlock_lock = new_posix_lock (&flock, old_lock->client, + old_lock->client_pid, &old_lock->owner, + old_lock->fd); + GF_VALIDATE_OR_GOTO (this->name, unlock_lock, out); + ret = 0; + + __insert_and_merge (pl_inode, unlock_lock); + + __grant_blocked_locks (this, pl_inode, &granted_list); + + list_for_each_entry_safe (lock, tmp, &granted_list, list) { + list_del_init (&lock->list); + + pl_trace_out (this, lock->frame, NULL, NULL, F_SETLKW, + &lock->user_flock, 0, 0, NULL); + + STACK_UNWIND_STRICT (lk, lock->frame, 0, 0, + &lock->user_flock, NULL); + + GF_FREE (lock); + } + +out: + return ret; +} int pl_setlk (xlator_t *this, pl_inode_t *pl_inode, posix_lock_t *lock, @@ -921,21 +1025,38 @@ pl_setlk (xlator_t *this, pl_inode_t *pl_inode, posix_lock_t *lock, pthread_mutex_lock (&pl_inode->mutex); { + /* Send unlock before the actual lock to + prevent lock upgrade / downgrade + problems only if: + - it is a blocking call + - it has other conflicting locks + */ + + if (can_block && + !(__is_lock_grantable (pl_inode, lock))) { + ret = pl_send_prelock_unlock (this, pl_inode, + lock); + if (ret) + gf_log (this->name, GF_LOG_DEBUG, + "Could not send pre-lock " + "unlock"); + } + if (__is_lock_grantable (pl_inode, lock)) { gf_log (this->name, GF_LOG_TRACE, - "%s (pid=%d) lk-owner:%"PRIu64" %"PRId64" - %"PRId64" => OK", + "%s (pid=%d) lk-owner:%s %"PRId64" - %"PRId64" => OK", lock->fl_type == F_UNLCK ? "Unlock" : "Lock", lock->client_pid, - lock->owner, + lkowner_utoa (&lock->owner), lock->user_flock.l_start, lock->user_flock.l_len); __insert_and_merge (pl_inode, lock); } else if (can_block) { gf_log (this->name, GF_LOG_TRACE, - "%s (pid=%d) lk-owner:%"PRIu64" %"PRId64" - %"PRId64" => Blocked", + "%s (pid=%d) lk-owner:%s %"PRId64" - %"PRId64" => Blocked", lock->fl_type == F_UNLCK ? "Unlock" : "Lock", lock->client_pid, - lock->owner, + lkowner_utoa (&lock->owner), lock->user_flock.l_start, lock->user_flock.l_len); lock->blocked = 1; @@ -943,10 +1064,10 @@ pl_setlk (xlator_t *this, pl_inode_t *pl_inode, posix_lock_t *lock, ret = -1; } else { gf_log (this->name, GF_LOG_TRACE, - "%s (pid=%d) lk-owner:%"PRIu64" %"PRId64" - %"PRId64" => NOK", + "%s (pid=%d) lk-owner:%s %"PRId64" - %"PRId64" => NOK", lock->fl_type == F_UNLCK ? "Unlock" : "Lock", lock->client_pid, - lock->owner, + lkowner_utoa (&lock->owner), lock->user_flock.l_start, lock->user_flock.l_len); errno = EAGAIN; @@ -968,7 +1089,7 @@ pl_getlk (pl_inode_t *pl_inode, posix_lock_t *lock) { posix_lock_t *conf = NULL; - conf = first_overlap (pl_inode, lock); + conf = first_conflicting_overlap (pl_inode, lock); if (conf == NULL) { lock->fl_type = F_UNLCK; @@ -977,3 +1098,124 @@ pl_getlk (pl_inode_t *pl_inode, posix_lock_t *lock) return conf; } + + +struct _lock_table * +pl_lock_table_new (void) +{ + struct _lock_table *new = NULL; + + new = GF_CALLOC (1, sizeof (struct _lock_table), gf_common_mt_lock_table); + if (new == NULL) { + goto out; + } + INIT_LIST_HEAD (&new->entrylk_lockers); + INIT_LIST_HEAD (&new->inodelk_lockers); + LOCK_INIT (&new->lock); +out: + return new; +} + + +int +pl_add_locker (struct _lock_table *table, const char *volume, + loc_t *loc, fd_t *fd, pid_t pid, gf_lkowner_t *owner, + glusterfs_fop_t type) +{ + int32_t ret = -1; + struct _locker *new = NULL; + + GF_VALIDATE_OR_GOTO ("lock-table", table, out); + GF_VALIDATE_OR_GOTO ("lock-table", volume, out); + + new = GF_CALLOC (1, sizeof (struct _locker), gf_common_mt_locker); + if (new == NULL) { + goto out; + } + INIT_LIST_HEAD (&new->lockers); + + new->volume = gf_strdup (volume); + + if (fd == NULL) { + loc_copy (&new->loc, loc); + } else { + new->fd = fd_ref (fd); + } + + new->pid = pid; + new->owner = *owner; + + LOCK (&table->lock); + { + if (type == GF_FOP_ENTRYLK) + list_add_tail (&new->lockers, &table->entrylk_lockers); + else + list_add_tail (&new->lockers, &table->inodelk_lockers); + } + UNLOCK (&table->lock); +out: + return ret; +} + +int +pl_del_locker (struct _lock_table *table, const char *volume, + loc_t *loc, fd_t *fd, gf_lkowner_t *owner, glusterfs_fop_t type) +{ + struct _locker *locker = NULL; + struct _locker *tmp = NULL; + int32_t ret = -1; + struct list_head *head = NULL; + struct list_head del; + + GF_VALIDATE_OR_GOTO ("lock-table", table, out); + GF_VALIDATE_OR_GOTO ("lock-table", volume, out); + + INIT_LIST_HEAD (&del); + + LOCK (&table->lock); + { + if (type == GF_FOP_ENTRYLK) { + head = &table->entrylk_lockers; + } else { + head = &table->inodelk_lockers; + } + + list_for_each_entry_safe (locker, tmp, head, lockers) { + if (!is_same_lkowner (&locker->owner, owner) || + strcmp (locker->volume, volume)) + continue; + + /* + * It is possible for inodelk lock to come on anon-fd + * and inodelk unlock to come on normal fd in case of + * client re-opens. So don't check for fds to be equal. + */ + if (locker->fd && fd) + list_move_tail (&locker->lockers, &del); + else if (locker->loc.inode && loc && + (locker->loc.inode == loc->inode)) + list_move_tail (&locker->lockers, &del); + } + } + UNLOCK (&table->lock); + + tmp = NULL; + locker = NULL; + + list_for_each_entry_safe (locker, tmp, &del, lockers) { + list_del_init (&locker->lockers); + if (locker->fd) + fd_unref (locker->fd); + else + loc_wipe (&locker->loc); + + GF_FREE (locker->volume); + GF_FREE (locker); + } + + ret = 0; +out: + return ret; + +} + |
