]>
Commit | Line | Data |
---|---|---|
ed2a6bee DM |
1 | From 901025d2f3194b4868980c8ba80df4cc0aa1282c Mon Sep 17 00:00:00 2001 |
2 | From: David Teigland <teigland@redhat.com> | |
3 | Date: Wed, 2 Mar 2011 14:20:04 -0600 | |
4 | Subject: [PATCH 1/1] dlm: make plock operation killable | |
5 | ||
6 | Allow processes blocked on plock requests to be interrupted | |
7 | when they are killed. This leaves the problem of cleaning | |
8 | up the lock state in userspace. This has three parts: | |
9 | ||
10 | 1. Add a flag to unlock operations sent to userspace | |
11 | indicating the file is being closed. Userspace will | |
12 | then look for and clear any waiting plock operations that | |
13 | were abandoned by an interrupted process. | |
14 | ||
15 | 2. Queue an unlock-close operation (like in 1) to clean up | |
16 | userspace from an interrupted plock request. This is needed | |
17 | because the vfs will not send a cleanup-unlock if it sees no | |
18 | locks on the file, which it won't if the interrupted operation | |
19 | was the only one. | |
20 | ||
21 | 3. Do not use replies from userspace for unlock-close operations | |
22 | because they are unnecessary (they are just cleaning up for the | |
23 | process which did not make an unlock call). This also simplifies | |
24 | the new unlock-close generated from point 2. | |
25 | ||
26 | Signed-off-by: David Teigland <teigland@redhat.com> | |
27 | --- | |
28 | fs/dlm/plock.c | 65 ++++++++++++++++++++++++++++++++++++++++++--- | |
29 | include/linux/dlm_plock.h | 6 +++- | |
30 | 2 files changed, 65 insertions(+), 6 deletions(-) | |
31 | ||
32 | diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c | |
33 | index 30d8b85..e2b8780 100644 | |
34 | --- a/fs/dlm/plock.c | |
35 | +++ b/fs/dlm/plock.c | |
36 | @@ -71,6 +71,36 @@ static void send_op(struct plock_op *op) | |
37 | wake_up(&send_wq); | |
38 | } | |
39 | ||
40 | +/* If a process was killed while waiting for the only plock on a file, | |
41 | + locks_remove_posix will not see any lock on the file so it won't | |
42 | + send an unlock-close to us to pass on to userspace to clean up the | |
43 | + abandoned waiter. So, we have to insert the unlock-close when the | |
44 | + lock call is interrupted. */ | |
45 | + | |
46 | +static void do_unlock_close(struct dlm_ls *ls, u64 number, | |
47 | + struct file *file, struct file_lock *fl) | |
48 | +{ | |
49 | + struct plock_op *op; | |
50 | + | |
51 | + op = kzalloc(sizeof(*op), GFP_NOFS); | |
52 | + if (!op) | |
53 | + return; | |
54 | + | |
55 | + op->info.optype = DLM_PLOCK_OP_UNLOCK; | |
56 | + op->info.pid = fl->fl_pid; | |
57 | + op->info.fsid = ls->ls_global_id; | |
58 | + op->info.number = number; | |
59 | + op->info.start = 0; | |
60 | + op->info.end = OFFSET_MAX; | |
61 | + if (fl->fl_lmops && fl->fl_lmops->fl_grant) | |
62 | + op->info.owner = (__u64) fl->fl_pid; | |
63 | + else | |
64 | + op->info.owner = (__u64)(long) fl->fl_owner; | |
65 | + | |
66 | + op->info.flags |= DLM_PLOCK_FL_CLOSE; | |
67 | + send_op(op); | |
68 | +} | |
69 | + | |
70 | int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, | |
71 | int cmd, struct file_lock *fl) | |
72 | { | |
73 | @@ -114,9 +144,19 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, | |
74 | ||
75 | send_op(op); | |
76 | ||
77 | - if (xop->callback == NULL) | |
78 | - wait_event(recv_wq, (op->done != 0)); | |
79 | - else { | |
80 | + if (xop->callback == NULL) { | |
81 | + rv = wait_event_killable(recv_wq, (op->done != 0)); | |
82 | + if (rv == -ERESTARTSYS) { | |
83 | + log_debug(ls, "dlm_posix_lock: wait killed %llx", | |
84 | + (unsigned long long)number); | |
85 | + spin_lock(&ops_lock); | |
86 | + list_del(&op->list); | |
87 | + spin_unlock(&ops_lock); | |
88 | + kfree(xop); | |
89 | + do_unlock_close(ls, number, file, fl); | |
90 | + goto out; | |
91 | + } | |
92 | + } else { | |
93 | rv = FILE_LOCK_DEFERRED; | |
94 | goto out; | |
95 | } | |
96 | @@ -233,6 +273,13 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file, | |
97 | else | |
98 | op->info.owner = (__u64)(long) fl->fl_owner; | |
99 | ||
100 | + if (fl->fl_flags & FL_CLOSE) { | |
101 | + op->info.flags |= DLM_PLOCK_FL_CLOSE; | |
102 | + send_op(op); | |
103 | + rv = 0; | |
104 | + goto out; | |
105 | + } | |
106 | + | |
107 | send_op(op); | |
108 | wait_event(recv_wq, (op->done != 0)); | |
109 | ||
110 | @@ -334,7 +381,10 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count, | |
111 | spin_lock(&ops_lock); | |
112 | if (!list_empty(&send_list)) { | |
113 | op = list_entry(send_list.next, struct plock_op, list); | |
114 | - list_move(&op->list, &recv_list); | |
115 | + if (op->info.flags & DLM_PLOCK_FL_CLOSE) | |
116 | + list_del(&op->list); | |
117 | + else | |
118 | + list_move(&op->list, &recv_list); | |
119 | memcpy(&info, &op->info, sizeof(info)); | |
120 | } | |
121 | spin_unlock(&ops_lock); | |
122 | @@ -342,6 +392,13 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count, | |
123 | if (!op) | |
124 | return -EAGAIN; | |
125 | ||
126 | + /* there is no need to get a reply from userspace for unlocks | |
127 | + that were generated by the vfs cleaning up for a close | |
128 | + (the process did not make an unlock call). */ | |
129 | + | |
130 | + if (op->info.flags & DLM_PLOCK_FL_CLOSE) | |
131 | + kfree(op); | |
132 | + | |
133 | if (copy_to_user(u, &info, sizeof(info))) | |
134 | return -EFAULT; | |
135 | return sizeof(info); | |
136 | diff --git a/include/linux/dlm_plock.h b/include/linux/dlm_plock.h | |
137 | index 2dd2124..3b1cc1b 100644 | |
138 | --- a/include/linux/dlm_plock.h | |
139 | +++ b/include/linux/dlm_plock.h | |
140 | @@ -14,7 +14,7 @@ | |
141 | #define DLM_PLOCK_MISC_NAME "dlm_plock" | |
142 | ||
143 | #define DLM_PLOCK_VERSION_MAJOR 1 | |
144 | -#define DLM_PLOCK_VERSION_MINOR 1 | |
145 | +#define DLM_PLOCK_VERSION_MINOR 2 | |
146 | #define DLM_PLOCK_VERSION_PATCH 0 | |
147 | ||
148 | enum { | |
149 | @@ -23,12 +23,14 @@ enum { | |
150 | DLM_PLOCK_OP_GET, | |
151 | }; | |
152 | ||
153 | +#define DLM_PLOCK_FL_CLOSE 1 | |
154 | + | |
155 | struct dlm_plock_info { | |
156 | __u32 version[3]; | |
157 | __u8 optype; | |
158 | __u8 ex; | |
159 | __u8 wait; | |
160 | - __u8 pad; | |
161 | + __u8 flags; | |
162 | __u32 pid; | |
163 | __s32 nodeid; | |
164 | __s32 rv; | |
165 | -- | |
166 | 1.7.2.5 | |
167 |