summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavan Sondur <pavan@gluster.com>2010-10-05 06:40:32 +0000
committerVijay Bellur <vijay@dev.gluster.com>2010-10-05 05:34:56 -0700
commit79db3aced2ffca84a696192343d5b811833eb671 (patch)
tree8240b3f9844c0e3027449aa4478b58296dd1921f
parent99ac72b988f0ccd0bf876cf3e2326b8406f71461 (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.c70
-rw-r--r--xlators/features/locks/src/locks.h1
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