From ef4005be3ac7f0f266f139c5b3d66538e35b924c Mon Sep 17 00:00:00 2001 From: Pavan Sondur Date: Mon, 18 Oct 2010 03:16:05 +0000 Subject: features/locks: Handle upgrade/downgrade of locks properly. Signed-off-by: root Signed-off-by: Vijay Bellur BUG: 1017 (Locking deadlock when upgrading lock) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=1017 --- xlators/features/locks/src/common.c | 70 +++++++++++++++++++++++++++++++++++-- xlators/features/locks/src/locks.h | 1 + 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/xlators/features/locks/src/common.c b/xlators/features/locks/src/common.c index 3df1312e5..483d7bf57 100644 --- a/xlators/features/locks/src/common.c +++ b/xlators/features/locks/src/common.c @@ -42,7 +42,9 @@ 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) { @@ -468,6 +470,7 @@ new_posix_lock (struct flock *flock, transport_t *transport, pid_t client_pid, lock->transport = transport; lock->fd_num = fd_to_fdnum (fd); + lock->fd = fd; lock->client_pid = client_pid; lock->owner = owner; @@ -507,12 +510,11 @@ posix_lock_to_flock (posix_lock_t *lock, struct flock *flock) 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); + list_add_tail (&lock->list, &pl_inode->ext_list); return; } @@ -860,6 +862,56 @@ 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 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 = 0; + + 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->transport, + old_lock->client_pid, old_lock->owner, + old_lock->fd); + if (!unlock_lock) { + gf_log (this->name, GF_LOG_ERROR, + "Out of memory"); + ret = -1; + goto out; + } + + __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 (lock->frame, 0, 0, &lock->user_flock); + + FREE (lock); + } + +out: + + return ret; +} int pl_setlk (xlator_t *this, pl_inode_t *pl_inode, posix_lock_t *lock, @@ -871,6 +923,18 @@ 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 + */ + + 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", diff --git a/xlators/features/locks/src/locks.h b/xlators/features/locks/src/locks.h index e89092811..1bbbee119 100644 --- a/xlators/features/locks/src/locks.h +++ b/xlators/features/locks/src/locks.h @@ -44,6 +44,7 @@ struct __posix_lock { xlator_t *this; /* required for blocked locks */ unsigned long fd_num; + fd_t *fd; call_frame_t *frame; /* These two together serve to uniquely identify each process -- cgit