diff options
Diffstat (limited to 'fs/dlm')
-rw-r--r-- | fs/dlm/plock.c | 65 |
1 files changed, 61 insertions, 4 deletions
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index 30d8b85febb..e2b87800436 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c | |||
@@ -71,6 +71,36 @@ static void send_op(struct plock_op *op) | |||
71 | wake_up(&send_wq); | 71 | wake_up(&send_wq); |
72 | } | 72 | } |
73 | 73 | ||
74 | /* If a process was killed while waiting for the only plock on a file, | ||
75 | locks_remove_posix will not see any lock on the file so it won't | ||
76 | send an unlock-close to us to pass on to userspace to clean up the | ||
77 | abandoned waiter. So, we have to insert the unlock-close when the | ||
78 | lock call is interrupted. */ | ||
79 | |||
80 | static void do_unlock_close(struct dlm_ls *ls, u64 number, | ||
81 | struct file *file, struct file_lock *fl) | ||
82 | { | ||
83 | struct plock_op *op; | ||
84 | |||
85 | op = kzalloc(sizeof(*op), GFP_NOFS); | ||
86 | if (!op) | ||
87 | return; | ||
88 | |||
89 | op->info.optype = DLM_PLOCK_OP_UNLOCK; | ||
90 | op->info.pid = fl->fl_pid; | ||
91 | op->info.fsid = ls->ls_global_id; | ||
92 | op->info.number = number; | ||
93 | op->info.start = 0; | ||
94 | op->info.end = OFFSET_MAX; | ||
95 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) | ||
96 | op->info.owner = (__u64) fl->fl_pid; | ||
97 | else | ||
98 | op->info.owner = (__u64)(long) fl->fl_owner; | ||
99 | |||
100 | op->info.flags |= DLM_PLOCK_FL_CLOSE; | ||
101 | send_op(op); | ||
102 | } | ||
103 | |||
74 | int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, | 104 | int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, |
75 | int cmd, struct file_lock *fl) | 105 | int cmd, struct file_lock *fl) |
76 | { | 106 | { |
@@ -114,9 +144,19 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, | |||
114 | 144 | ||
115 | send_op(op); | 145 | send_op(op); |
116 | 146 | ||
117 | if (xop->callback == NULL) | 147 | if (xop->callback == NULL) { |
118 | wait_event(recv_wq, (op->done != 0)); | 148 | rv = wait_event_killable(recv_wq, (op->done != 0)); |
119 | else { | 149 | if (rv == -ERESTARTSYS) { |
150 | log_debug(ls, "dlm_posix_lock: wait killed %llx", | ||
151 | (unsigned long long)number); | ||
152 | spin_lock(&ops_lock); | ||
153 | list_del(&op->list); | ||
154 | spin_unlock(&ops_lock); | ||
155 | kfree(xop); | ||
156 | do_unlock_close(ls, number, file, fl); | ||
157 | goto out; | ||
158 | } | ||
159 | } else { | ||
120 | rv = FILE_LOCK_DEFERRED; | 160 | rv = FILE_LOCK_DEFERRED; |
121 | goto out; | 161 | goto out; |
122 | } | 162 | } |
@@ -233,6 +273,13 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file, | |||
233 | else | 273 | else |
234 | op->info.owner = (__u64)(long) fl->fl_owner; | 274 | op->info.owner = (__u64)(long) fl->fl_owner; |
235 | 275 | ||
276 | if (fl->fl_flags & FL_CLOSE) { | ||
277 | op->info.flags |= DLM_PLOCK_FL_CLOSE; | ||
278 | send_op(op); | ||
279 | rv = 0; | ||
280 | goto out; | ||
281 | } | ||
282 | |||
236 | send_op(op); | 283 | send_op(op); |
237 | wait_event(recv_wq, (op->done != 0)); | 284 | wait_event(recv_wq, (op->done != 0)); |
238 | 285 | ||
@@ -334,7 +381,10 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count, | |||
334 | spin_lock(&ops_lock); | 381 | spin_lock(&ops_lock); |
335 | if (!list_empty(&send_list)) { | 382 | if (!list_empty(&send_list)) { |
336 | op = list_entry(send_list.next, struct plock_op, list); | 383 | op = list_entry(send_list.next, struct plock_op, list); |
337 | list_move(&op->list, &recv_list); | 384 | if (op->info.flags & DLM_PLOCK_FL_CLOSE) |
385 | list_del(&op->list); | ||
386 | else | ||
387 | list_move(&op->list, &recv_list); | ||
338 | memcpy(&info, &op->info, sizeof(info)); | 388 | memcpy(&info, &op->info, sizeof(info)); |
339 | } | 389 | } |
340 | spin_unlock(&ops_lock); | 390 | spin_unlock(&ops_lock); |
@@ -342,6 +392,13 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count, | |||
342 | if (!op) | 392 | if (!op) |
343 | return -EAGAIN; | 393 | return -EAGAIN; |
344 | 394 | ||
395 | /* there is no need to get a reply from userspace for unlocks | ||
396 | that were generated by the vfs cleaning up for a close | ||
397 | (the process did not make an unlock call). */ | ||
398 | |||
399 | if (op->info.flags & DLM_PLOCK_FL_CLOSE) | ||
400 | kfree(op); | ||
401 | |||
345 | if (copy_to_user(u, &info, sizeof(info))) | 402 | if (copy_to_user(u, &info, sizeof(info))) |
346 | return -EFAULT; | 403 | return -EFAULT; |
347 | return sizeof(info); | 404 | return sizeof(info); |