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) |
