Эх сурвалжийг харах

[DLM] fix leaking user locks

User NOQUEUE lock requests to a remote node that failed with -EAGAIN were
never being removed from a process's list of locks.

Signed-off-by: David Teigland <teigland@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
David Teigland 19 жил өмнө
parent
commit
34e22bed19
2 өөрчлөгдсөн 20 нэмэгдсэн , 3 устгасан
  1. 4 3
      fs/dlm/lock.c
  2. 16 0
      fs/dlm/user.c

+ 4 - 3
fs/dlm/lock.c

@@ -526,6 +526,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
 	lkb->lkb_nodeid = -1;
 	lkb->lkb_nodeid = -1;
 	lkb->lkb_grmode = DLM_LOCK_IV;
 	lkb->lkb_grmode = DLM_LOCK_IV;
 	kref_init(&lkb->lkb_ref);
 	kref_init(&lkb->lkb_ref);
+	INIT_LIST_HEAD(&lkb->lkb_ownqueue);
 
 
 	get_random_bytes(&bucket, sizeof(bucket));
 	get_random_bytes(&bucket, sizeof(bucket));
 	bucket &= (ls->ls_lkbtbl_size - 1);
 	bucket &= (ls->ls_lkbtbl_size - 1);
@@ -3705,7 +3706,7 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
 		goto out_put;
 		goto out_put;
 
 
 	spin_lock(&ua->proc->locks_spin);
 	spin_lock(&ua->proc->locks_spin);
-	list_del(&lkb->lkb_ownqueue);
+	list_del_init(&lkb->lkb_ownqueue);
 	spin_unlock(&ua->proc->locks_spin);
 	spin_unlock(&ua->proc->locks_spin);
 
 
 	/* this removes the reference for the proc->locks list added by
 	/* this removes the reference for the proc->locks list added by
@@ -3749,7 +3750,7 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
 	/* this lkb was removed from the WAITING queue */
 	/* this lkb was removed from the WAITING queue */
 	if (lkb->lkb_grmode == DLM_LOCK_IV) {
 	if (lkb->lkb_grmode == DLM_LOCK_IV) {
 		spin_lock(&ua->proc->locks_spin);
 		spin_lock(&ua->proc->locks_spin);
-		list_del(&lkb->lkb_ownqueue);
+		list_del_init(&lkb->lkb_ownqueue);
 		spin_unlock(&ua->proc->locks_spin);
 		spin_unlock(&ua->proc->locks_spin);
 		unhold_lkb(lkb);
 		unhold_lkb(lkb);
 	}
 	}
@@ -3817,7 +3818,7 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
 			unhold_lkb(lkb);
 			unhold_lkb(lkb);
 		}
 		}
 
 
-		list_del(&lkb->lkb_ownqueue);
+		list_del_init(&lkb->lkb_ownqueue);
 
 
 		if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) {
 		if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) {
 			lkb->lkb_flags |= DLM_IFL_ORPHAN;
 			lkb->lkb_flags |= DLM_IFL_ORPHAN;

+ 16 - 0
fs/dlm/user.c

@@ -133,6 +133,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
 	struct dlm_ls *ls;
 	struct dlm_ls *ls;
 	struct dlm_user_args *ua;
 	struct dlm_user_args *ua;
 	struct dlm_user_proc *proc;
 	struct dlm_user_proc *proc;
+	int remove_ownqueue = 0;
 
 
 	/* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each
 	/* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each
 	   lkb before dealing with it.  We need to check this
 	   lkb before dealing with it.  We need to check this
@@ -171,6 +172,14 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
 		wake_up_interruptible(&proc->wait);
 		wake_up_interruptible(&proc->wait);
 	}
 	}
 
 
+	/* noqueue requests that fail may need to be removed from the
+	   proc's locks list, there should be a better way of detecting
+	   this situation than checking all these things... */
+	   
+	if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV &&
+	    ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
+		remove_ownqueue = 1;
+
 	/* We want to copy the lvb to userspace when the completion
 	/* We want to copy the lvb to userspace when the completion
 	   ast is read if the status is 0, the lock has an lvb and
 	   ast is read if the status is 0, the lock has an lvb and
 	   lvb_ops says we should.  We could probably have set_lvb_lock()
 	   lvb_ops says we should.  We could probably have set_lvb_lock()
@@ -185,6 +194,13 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
 		ua->update_user_lvb = 0;
 		ua->update_user_lvb = 0;
 
 
 	spin_unlock(&proc->asts_spin);
 	spin_unlock(&proc->asts_spin);
+
+	if (remove_ownqueue) {
+		spin_lock(&ua->proc->locks_spin);
+		list_del_init(&lkb->lkb_ownqueue);
+		spin_unlock(&ua->proc->locks_spin);
+		dlm_put_lkb(lkb);
+	}
  out:
  out:
 	mutex_unlock(&ls->ls_clear_proc_locks);
 	mutex_unlock(&ls->ls_clear_proc_locks);
 }
 }