diff options
Diffstat (limited to 'fs/dlm/plock.c')
| -rw-r--r-- | fs/dlm/plock.c | 91 | 
1 files changed, 80 insertions, 11 deletions
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index 30d8b85febb..f704458ea5f 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -71,6 +71,36 @@ static void send_op(struct plock_op *op)  	wake_up(&send_wq);  } +/* If a process was killed while waiting for the only plock on a file, +   locks_remove_posix will not see any lock on the file so it won't +   send an unlock-close to us to pass on to userspace to clean up the +   abandoned waiter.  So, we have to insert the unlock-close when the +   lock call is interrupted. */ + +static void do_unlock_close(struct dlm_ls *ls, u64 number, +			    struct file *file, struct file_lock *fl) +{ +	struct plock_op *op; + +	op = kzalloc(sizeof(*op), GFP_NOFS); +	if (!op) +		return; + +	op->info.optype		= DLM_PLOCK_OP_UNLOCK; +	op->info.pid		= fl->fl_pid; +	op->info.fsid		= ls->ls_global_id; +	op->info.number		= number; +	op->info.start		= 0; +	op->info.end		= OFFSET_MAX; +	if (fl->fl_lmops && fl->fl_lmops->lm_grant) +		op->info.owner	= (__u64) fl->fl_pid; +	else +		op->info.owner	= (__u64)(long) fl->fl_owner; + +	op->info.flags |= DLM_PLOCK_FL_CLOSE; +	send_op(op); +} +  int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,  		   int cmd, struct file_lock *fl)  { @@ -98,11 +128,11 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,  	op->info.number		= number;  	op->info.start		= fl->fl_start;  	op->info.end		= fl->fl_end; -	if (fl->fl_lmops && fl->fl_lmops->fl_grant) { +	if (fl->fl_lmops && fl->fl_lmops->lm_grant) {  		/* fl_owner is lockd which doesn't distinguish  		   processes on the nfs client */  		op->info.owner	= (__u64) fl->fl_pid; -		xop->callback	= fl->fl_lmops->fl_grant; +		xop->callback	= fl->fl_lmops->lm_grant;  		locks_init_lock(&xop->flc);  		locks_copy_lock(&xop->flc, fl);  		xop->fl		= fl; @@ -114,9 +144,19 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,  	send_op(op); -	if (xop->callback == NULL) -		wait_event(recv_wq, (op->done != 0)); -	else { +	if (xop->callback == NULL) { +		rv = wait_event_killable(recv_wq, (op->done != 0)); +		if (rv == -ERESTARTSYS) { +			log_debug(ls, "dlm_posix_lock: wait killed %llx", +				  (unsigned long long)number); +			spin_lock(&ops_lock); +			list_del(&op->list); +			spin_unlock(&ops_lock); +			kfree(xop); +			do_unlock_close(ls, number, file, fl); +			goto out; +		} +	} else {  		rv = FILE_LOCK_DEFERRED;  		goto out;  	} @@ -207,6 +247,7 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,  	struct dlm_ls *ls;  	struct plock_op *op;  	int rv; +	unsigned char fl_flags = fl->fl_flags;  	ls = dlm_find_lockspace_local(lockspace);  	if (!ls) @@ -218,9 +259,18 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,  		goto out;  	} -	if (posix_lock_file_wait(file, fl) < 0) -		log_error(ls, "dlm_posix_unlock: vfs unlock error %llx", -			  (unsigned long long)number); +	/* cause the vfs unlock to return ENOENT if lock is not found */ +	fl->fl_flags |= FL_EXISTS; + +	rv = posix_lock_file_wait(file, fl); +	if (rv == -ENOENT) { +		rv = 0; +		goto out_free; +	} +	if (rv < 0) { +		log_error(ls, "dlm_posix_unlock: vfs unlock error %d %llx", +			  rv, (unsigned long long)number); +	}  	op->info.optype		= DLM_PLOCK_OP_UNLOCK;  	op->info.pid		= fl->fl_pid; @@ -228,11 +278,18 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,  	op->info.number		= number;  	op->info.start		= fl->fl_start;  	op->info.end		= fl->fl_end; -	if (fl->fl_lmops && fl->fl_lmops->fl_grant) +	if (fl->fl_lmops && fl->fl_lmops->lm_grant)  		op->info.owner	= (__u64) fl->fl_pid;  	else  		op->info.owner	= (__u64)(long) fl->fl_owner; +	if (fl->fl_flags & FL_CLOSE) { +		op->info.flags |= DLM_PLOCK_FL_CLOSE; +		send_op(op); +		rv = 0; +		goto out; +	} +  	send_op(op);  	wait_event(recv_wq, (op->done != 0)); @@ -249,9 +306,11 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,  	if (rv == -ENOENT)  		rv = 0; +out_free:  	kfree(op);  out:  	dlm_put_lockspace(ls); +	fl->fl_flags = fl_flags;  	return rv;  }  EXPORT_SYMBOL_GPL(dlm_posix_unlock); @@ -280,7 +339,7 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,  	op->info.number		= number;  	op->info.start		= fl->fl_start;  	op->info.end		= fl->fl_end; -	if (fl->fl_lmops && fl->fl_lmops->fl_grant) +	if (fl->fl_lmops && fl->fl_lmops->lm_grant)  		op->info.owner	= (__u64) fl->fl_pid;  	else  		op->info.owner	= (__u64)(long) fl->fl_owner; @@ -334,7 +393,10 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,  	spin_lock(&ops_lock);  	if (!list_empty(&send_list)) {  		op = list_entry(send_list.next, struct plock_op, list); -		list_move(&op->list, &recv_list); +		if (op->info.flags & DLM_PLOCK_FL_CLOSE) +			list_del(&op->list); +		else +			list_move(&op->list, &recv_list);  		memcpy(&info, &op->info, sizeof(info));  	}  	spin_unlock(&ops_lock); @@ -342,6 +404,13 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,  	if (!op)  		return -EAGAIN; +	/* there is no need to get a reply from userspace for unlocks +	   that were generated by the vfs cleaning up for a close +	   (the process did not make an unlock call). */ + +	if (op->info.flags & DLM_PLOCK_FL_CLOSE) +		kfree(op); +  	if (copy_to_user(u, &info, sizeof(info)))  		return -EFAULT;  	return sizeof(info);  | 
