diff options
-rw-r--r-- | fs/gfs2/locking/dlm/plock.c | 109 | ||||
-rw-r--r-- | fs/gfs2/ops_file.c | 5 |
2 files changed, 104 insertions, 10 deletions
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 1dd4215b83d0..f82495e18c2d 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c | |||
@@ -25,6 +25,15 @@ struct plock_op { | |||
25 | struct gdlm_plock_info info; | 25 | struct gdlm_plock_info info; |
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct plock_xop { | ||
29 | struct plock_op xop; | ||
30 | void *callback; | ||
31 | void *fl; | ||
32 | void *file; | ||
33 | struct file_lock flc; | ||
34 | }; | ||
35 | |||
36 | |||
28 | static inline void set_version(struct gdlm_plock_info *info) | 37 | static inline void set_version(struct gdlm_plock_info *info) |
29 | { | 38 | { |
30 | info->version[0] = GDLM_PLOCK_VERSION_MAJOR; | 39 | info->version[0] = GDLM_PLOCK_VERSION_MAJOR; |
@@ -64,12 +73,14 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name, | |||
64 | { | 73 | { |
65 | struct gdlm_ls *ls = lockspace; | 74 | struct gdlm_ls *ls = lockspace; |
66 | struct plock_op *op; | 75 | struct plock_op *op; |
76 | struct plock_xop *xop; | ||
67 | int rv; | 77 | int rv; |
68 | 78 | ||
69 | op = kzalloc(sizeof(*op), GFP_KERNEL); | 79 | xop = kzalloc(sizeof(*xop), GFP_KERNEL); |
70 | if (!op) | 80 | if (!xop) |
71 | return -ENOMEM; | 81 | return -ENOMEM; |
72 | 82 | ||
83 | op = &xop->xop; | ||
73 | op->info.optype = GDLM_PLOCK_OP_LOCK; | 84 | op->info.optype = GDLM_PLOCK_OP_LOCK; |
74 | op->info.pid = fl->fl_pid; | 85 | op->info.pid = fl->fl_pid; |
75 | op->info.ex = (fl->fl_type == F_WRLCK); | 86 | op->info.ex = (fl->fl_type == F_WRLCK); |
@@ -79,9 +90,21 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name, | |||
79 | op->info.start = fl->fl_start; | 90 | op->info.start = fl->fl_start; |
80 | op->info.end = fl->fl_end; | 91 | op->info.end = fl->fl_end; |
81 | op->info.owner = (__u64)(long) fl->fl_owner; | 92 | op->info.owner = (__u64)(long) fl->fl_owner; |
93 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) { | ||
94 | xop->callback = fl->fl_lmops->fl_grant; | ||
95 | locks_init_lock(&xop->flc); | ||
96 | locks_copy_lock(&xop->flc, fl); | ||
97 | xop->fl = fl; | ||
98 | xop->file = file; | ||
99 | } else | ||
100 | xop->callback = NULL; | ||
82 | 101 | ||
83 | send_op(op); | 102 | send_op(op); |
84 | wait_event(recv_wq, (op->done != 0)); | 103 | |
104 | if (xop->callback == NULL) | ||
105 | wait_event(recv_wq, (op->done != 0)); | ||
106 | else | ||
107 | return -EINPROGRESS; | ||
85 | 108 | ||
86 | spin_lock(&ops_lock); | 109 | spin_lock(&ops_lock); |
87 | if (!list_empty(&op->list)) { | 110 | if (!list_empty(&op->list)) { |
@@ -99,7 +122,63 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name, | |||
99 | (unsigned long long)name->ln_number); | 122 | (unsigned long long)name->ln_number); |
100 | } | 123 | } |
101 | 124 | ||
102 | kfree(op); | 125 | kfree(xop); |
126 | return rv; | ||
127 | } | ||
128 | |||
129 | /* Returns failure iff a succesful lock operation should be canceled */ | ||
130 | static int gdlm_plock_callback(struct plock_op *op) | ||
131 | { | ||
132 | struct file *file; | ||
133 | struct file_lock *fl; | ||
134 | struct file_lock *flc; | ||
135 | int (*notify)(void *, void *, int) = NULL; | ||
136 | struct plock_xop *xop = (struct plock_xop *)op; | ||
137 | int rv = 0; | ||
138 | |||
139 | spin_lock(&ops_lock); | ||
140 | if (!list_empty(&op->list)) { | ||
141 | printk(KERN_INFO "plock op on list\n"); | ||
142 | list_del(&op->list); | ||
143 | } | ||
144 | spin_unlock(&ops_lock); | ||
145 | |||
146 | /* check if the following 2 are still valid or make a copy */ | ||
147 | file = xop->file; | ||
148 | flc = &xop->flc; | ||
149 | fl = xop->fl; | ||
150 | notify = xop->callback; | ||
151 | |||
152 | if (op->info.rv) { | ||
153 | notify(flc, NULL, op->info.rv); | ||
154 | goto out; | ||
155 | } | ||
156 | |||
157 | /* got fs lock; bookkeep locally as well: */ | ||
158 | flc->fl_flags &= ~FL_SLEEP; | ||
159 | if (posix_lock_file(file, flc, NULL)) { | ||
160 | /* | ||
161 | * This can only happen in the case of kmalloc() failure. | ||
162 | * The filesystem's own lock is the authoritative lock, | ||
163 | * so a failure to get the lock locally is not a disaster. | ||
164 | * As long as GFS cannot reliably cancel locks (especially | ||
165 | * in a low-memory situation), we're better off ignoring | ||
166 | * this failure than trying to recover. | ||
167 | */ | ||
168 | log_error("gdlm_plock: vfs lock error file %p fl %p", | ||
169 | file, fl); | ||
170 | } | ||
171 | |||
172 | rv = notify(flc, NULL, 0); | ||
173 | if (rv) { | ||
174 | /* XXX: We need to cancel the fs lock here: */ | ||
175 | printk("gfs2 lock granted after lock request failed;" | ||
176 | " dangling lock!\n"); | ||
177 | goto out; | ||
178 | } | ||
179 | |||
180 | out: | ||
181 | kfree(xop); | ||
103 | return rv; | 182 | return rv; |
104 | } | 183 | } |
105 | 184 | ||
@@ -138,6 +217,9 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name, | |||
138 | 217 | ||
139 | rv = op->info.rv; | 218 | rv = op->info.rv; |
140 | 219 | ||
220 | if (rv == -ENOENT) | ||
221 | rv = 0; | ||
222 | |||
141 | kfree(op); | 223 | kfree(op); |
142 | return rv; | 224 | return rv; |
143 | } | 225 | } |
@@ -161,6 +243,7 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name, | |||
161 | op->info.start = fl->fl_start; | 243 | op->info.start = fl->fl_start; |
162 | op->info.end = fl->fl_end; | 244 | op->info.end = fl->fl_end; |
163 | 245 | ||
246 | |||
164 | send_op(op); | 247 | send_op(op); |
165 | wait_event(recv_wq, (op->done != 0)); | 248 | wait_event(recv_wq, (op->done != 0)); |
166 | 249 | ||
@@ -173,9 +256,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name, | |||
173 | 256 | ||
174 | rv = op->info.rv; | 257 | rv = op->info.rv; |
175 | 258 | ||
176 | if (rv == 0) | 259 | fl->fl_type = F_UNLCK; |
177 | fl->fl_type = F_UNLCK; | 260 | if (rv == -ENOENT) |
178 | else if (rv > 0) { | 261 | rv = 0; |
262 | else if (rv == 0 && op->info.pid != fl->fl_pid) { | ||
179 | fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK; | 263 | fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK; |
180 | fl->fl_pid = op->info.pid; | 264 | fl->fl_pid = op->info.pid; |
181 | fl->fl_start = op->info.start; | 265 | fl->fl_start = op->info.start; |
@@ -243,9 +327,14 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, | |||
243 | } | 327 | } |
244 | spin_unlock(&ops_lock); | 328 | spin_unlock(&ops_lock); |
245 | 329 | ||
246 | if (found) | 330 | if (found) { |
247 | wake_up(&recv_wq); | 331 | struct plock_xop *xop; |
248 | else | 332 | xop = (struct plock_xop *)op; |
333 | if (xop->callback) | ||
334 | count = gdlm_plock_callback(op); | ||
335 | else | ||
336 | wake_up(&recv_wq); | ||
337 | } else | ||
249 | printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid, | 338 | printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid, |
250 | (unsigned long long)info.number); | 339 | (unsigned long long)info.number); |
251 | return count; | 340 | return count; |
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 48b248d7c823..329c4dcdecdb 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c | |||
@@ -520,6 +520,11 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl) | |||
520 | } | 520 | } |
521 | } | 521 | } |
522 | 522 | ||
523 | if (cmd == F_CANCELLK) { | ||
524 | /* Hack: */ | ||
525 | cmd = F_SETLK; | ||
526 | fl->fl_type = F_UNLCK; | ||
527 | } | ||
523 | if (IS_GETLK(cmd)) | 528 | if (IS_GETLK(cmd)) |
524 | return gfs2_lm_plock_get(sdp, &name, file, fl); | 529 | return gfs2_lm_plock_get(sdp, &name, file, fl); |
525 | else if (fl->fl_type == F_UNLCK) | 530 | else if (fl->fl_type == F_UNLCK) |