diff options
author | Pavan Sondur <pavan@gluster.com> | 2010-10-05 06:40:32 +0000 |
---|---|---|
committer | Vijay Bellur <vijay@dev.gluster.com> | 2010-10-05 05:34:56 -0700 |
commit | 79db3aced2ffca84a696192343d5b811833eb671 (patch) | |
tree | 8240b3f9844c0e3027449aa4478b58296dd1921f | |
parent | 99ac72b988f0ccd0bf876cf3e2326b8406f71461 (diff) |
features/locks: Handle lock upgrade and downgrade properly in locks.
Signed-off-by: Pavan Vilas Sondur <pavan@gluster.com>
Signed-off-by: Pavan Vilas Sondur <pavan@dev.gluster.com>
Signed-off-by: Vijay Bellur <vijay@dev.gluster.com>
BUG: 1017 (Locking deadlock when upgrading lock)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=1017
-rw-r--r-- | xlators/features/locks/src/common.c | 70 | ||||
-rw-r--r-- | 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 5b21b189c..e295e4fd5 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) { @@ -481,6 +483,7 @@ new_posix_lock (struct gf_flock *flock, void *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; @@ -521,12 +524,11 @@ posix_lock_to_flock (posix_lock_t *lock, struct gf_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; } @@ -920,6 +922,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 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 = 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); + + GF_FREE (lock); + } + +out: + + return ret; +} int pl_setlk (xlator_t *this, pl_inode_t *pl_inode, posix_lock_t *lock, @@ -931,6 +983,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 68c0c7522..614bddb64 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 |