Skip to content

Commit dc52cd2

Browse files
Alexander Aringteigland
authored andcommitted
fs: dlm: fix F_CANCELLK to cancel pending request
This patch fixes the current handling of F_CANCELLK by not just doing a unlock as we need to try to cancel a lock at first. A unlock makes sense on a non-blocking lock request but if it's a blocking lock request we need to cancel the request until it's not granted yet. This patch is fixing this behaviour by first try to cancel a lock request and if it's failed it's unlocking the lock which seems to be granted. Note: currently the nfs locking handling was disabled by commit 40595cd ("nfs: block notification on fs with its own ->lock"). However DLM was never being updated regarding to this change. Future patches will try to fix lockd lock requests for DLM. This patch is currently assuming the upstream DLM lockd handling is correct. Signed-off-by: Alexander Aring <[email protected]> Signed-off-by: David Teigland <[email protected]>
1 parent 568f915 commit dc52cd2

File tree

4 files changed

+98
-29
lines changed

4 files changed

+98
-29
lines changed

fs/dlm/plock.c

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,27 @@ static inline void set_version(struct dlm_plock_info *info)
4242
info->version[2] = DLM_PLOCK_VERSION_PATCH;
4343
}
4444

45+
static struct plock_op *plock_lookup_waiter(const struct dlm_plock_info *info)
46+
{
47+
struct plock_op *op = NULL, *iter;
48+
49+
list_for_each_entry(iter, &recv_list, list) {
50+
if (iter->info.fsid == info->fsid &&
51+
iter->info.number == info->number &&
52+
iter->info.owner == info->owner &&
53+
iter->info.pid == info->pid &&
54+
iter->info.start == info->start &&
55+
iter->info.end == info->end &&
56+
iter->info.ex == info->ex &&
57+
iter->info.wait) {
58+
op = iter;
59+
break;
60+
}
61+
}
62+
63+
return op;
64+
}
65+
4566
static int check_version(struct dlm_plock_info *info)
4667
{
4768
if ((DLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
@@ -334,6 +355,74 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
334355
}
335356
EXPORT_SYMBOL_GPL(dlm_posix_unlock);
336357

358+
/*
359+
* NOTE: This implementation can only handle async lock requests as nfs
360+
* do it. It cannot handle cancellation of a pending lock request sitting
361+
* in wait_event(), but for now only nfs is the only user local kernel
362+
* user.
363+
*/
364+
int dlm_posix_cancel(dlm_lockspace_t *lockspace, u64 number, struct file *file,
365+
struct file_lock *fl)
366+
{
367+
struct dlm_plock_info info;
368+
struct plock_op *op;
369+
struct dlm_ls *ls;
370+
int rv;
371+
372+
/* this only works for async request for now and nfs is the only
373+
* kernel user right now.
374+
*/
375+
if (WARN_ON_ONCE(!fl->fl_lmops || !fl->fl_lmops->lm_grant))
376+
return -EOPNOTSUPP;
377+
378+
ls = dlm_find_lockspace_local(lockspace);
379+
if (!ls)
380+
return -EINVAL;
381+
382+
memset(&info, 0, sizeof(info));
383+
info.pid = fl->fl_pid;
384+
info.ex = (fl->fl_type == F_WRLCK);
385+
info.fsid = ls->ls_global_id;
386+
dlm_put_lockspace(ls);
387+
info.number = number;
388+
info.start = fl->fl_start;
389+
info.end = fl->fl_end;
390+
info.owner = (__u64)fl->fl_pid;
391+
392+
rv = do_lock_cancel(&info);
393+
switch (rv) {
394+
case 0:
395+
spin_lock(&ops_lock);
396+
/* lock request to cancel must be on recv_list because
397+
* do_lock_cancel() synchronizes it.
398+
*/
399+
op = plock_lookup_waiter(&info);
400+
if (WARN_ON_ONCE(!op)) {
401+
rv = -ENOLCK;
402+
break;
403+
}
404+
405+
list_del(&op->list);
406+
spin_unlock(&ops_lock);
407+
WARN_ON(op->info.optype != DLM_PLOCK_OP_LOCK);
408+
op->data->callback(op->data->fl, -EINTR);
409+
dlm_release_plock_op(op);
410+
rv = -EINTR;
411+
break;
412+
case -ENOENT:
413+
/* if cancel wasn't successful we probably were to late
414+
* or it was a non-blocking lock request, so just unlock it.
415+
*/
416+
rv = dlm_posix_unlock(lockspace, number, file, fl);
417+
break;
418+
default:
419+
break;
420+
}
421+
422+
return rv;
423+
}
424+
EXPORT_SYMBOL_GPL(dlm_posix_cancel);
425+
337426
int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
338427
struct file_lock *fl)
339428
{
@@ -457,19 +546,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
457546
*/
458547
spin_lock(&ops_lock);
459548
if (info.wait) {
460-
list_for_each_entry(iter, &recv_list, list) {
461-
if (iter->info.fsid == info.fsid &&
462-
iter->info.number == info.number &&
463-
iter->info.owner == info.owner &&
464-
iter->info.pid == info.pid &&
465-
iter->info.start == info.start &&
466-
iter->info.end == info.end &&
467-
iter->info.ex == info.ex &&
468-
iter->info.wait) {
469-
op = iter;
470-
break;
471-
}
472-
}
549+
op = plock_lookup_waiter(&info);
473550
} else {
474551
list_for_each_entry(iter, &recv_list, list) {
475552
if (!iter->info.wait) {

fs/gfs2/file.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,17 +1436,14 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
14361436

14371437
if (!(fl->fl_flags & FL_POSIX))
14381438
return -ENOLCK;
1439-
if (cmd == F_CANCELLK) {
1440-
/* Hack: */
1441-
cmd = F_SETLK;
1442-
fl->fl_type = F_UNLCK;
1443-
}
14441439
if (unlikely(gfs2_withdrawn(sdp))) {
14451440
if (fl->fl_type == F_UNLCK)
14461441
locks_lock_file_wait(file, fl);
14471442
return -EIO;
14481443
}
1449-
if (IS_GETLK(cmd))
1444+
if (cmd == F_CANCELLK)
1445+
return dlm_posix_cancel(ls->ls_dlm, ip->i_no_addr, file, fl);
1446+
else if (IS_GETLK(cmd))
14501447
return dlm_posix_get(ls->ls_dlm, ip->i_no_addr, file, fl);
14511448
else if (fl->fl_type == F_UNLCK)
14521449
return dlm_posix_unlock(ls->ls_dlm, ip->i_no_addr, file, fl);

fs/ocfs2/stack_user.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -738,18 +738,11 @@ static int user_plock(struct ocfs2_cluster_connection *conn,
738738
*
739739
* Internally, fs/dlm will pass these to a misc device, which
740740
* a userspace daemon will read and write to.
741-
*
742-
* For now, cancel requests (which happen internally only),
743-
* are turned into unlocks. Most of this function taken from
744-
* gfs2_lock.
745741
*/
746742

747-
if (cmd == F_CANCELLK) {
748-
cmd = F_SETLK;
749-
fl->fl_type = F_UNLCK;
750-
}
751-
752-
if (IS_GETLK(cmd))
743+
if (cmd == F_CANCELLK)
744+
return dlm_posix_cancel(conn->cc_lockspace, ino, file, fl);
745+
else if (IS_GETLK(cmd))
753746
return dlm_posix_get(conn->cc_lockspace, ino, file, fl);
754747
else if (fl->fl_type == F_UNLCK)
755748
return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl);

include/linux/dlm_plock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
1111
int cmd, struct file_lock *fl);
1212
int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
1313
struct file_lock *fl);
14+
int dlm_posix_cancel(dlm_lockspace_t *lockspace, u64 number, struct file *file,
15+
struct file_lock *fl);
1416
int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
1517
struct file_lock *fl);
1618
#endif

0 commit comments

Comments
 (0)