0001
0002
0003
0004
0005
0006 #include <linux/fs.h>
0007 #include <linux/miscdevice.h>
0008 #include <linux/poll.h>
0009 #include <linux/dlm.h>
0010 #include <linux/dlm_plock.h>
0011 #include <linux/slab.h>
0012
0013 #include "dlm_internal.h"
0014 #include "lockspace.h"
0015
0016 static DEFINE_SPINLOCK(ops_lock);
0017 static LIST_HEAD(send_list);
0018 static LIST_HEAD(recv_list);
0019 static DECLARE_WAIT_QUEUE_HEAD(send_wq);
0020 static DECLARE_WAIT_QUEUE_HEAD(recv_wq);
0021
0022 struct plock_async_data {
0023 void *fl;
0024 void *file;
0025 struct file_lock flc;
0026 int (*callback)(struct file_lock *fl, int result);
0027 };
0028
0029 struct plock_op {
0030 struct list_head list;
0031 int done;
0032
0033 bool sigint;
0034 struct dlm_plock_info info;
0035
0036 struct plock_async_data *data;
0037 };
0038
0039 static inline void set_version(struct dlm_plock_info *info)
0040 {
0041 info->version[0] = DLM_PLOCK_VERSION_MAJOR;
0042 info->version[1] = DLM_PLOCK_VERSION_MINOR;
0043 info->version[2] = DLM_PLOCK_VERSION_PATCH;
0044 }
0045
0046 static int check_version(struct dlm_plock_info *info)
0047 {
0048 if ((DLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
0049 (DLM_PLOCK_VERSION_MINOR < info->version[1])) {
0050 log_print("plock device version mismatch: "
0051 "kernel (%u.%u.%u), user (%u.%u.%u)",
0052 DLM_PLOCK_VERSION_MAJOR,
0053 DLM_PLOCK_VERSION_MINOR,
0054 DLM_PLOCK_VERSION_PATCH,
0055 info->version[0],
0056 info->version[1],
0057 info->version[2]);
0058 return -EINVAL;
0059 }
0060 return 0;
0061 }
0062
0063 static void dlm_release_plock_op(struct plock_op *op)
0064 {
0065 kfree(op->data);
0066 kfree(op);
0067 }
0068
0069 static void send_op(struct plock_op *op)
0070 {
0071 set_version(&op->info);
0072 spin_lock(&ops_lock);
0073 list_add_tail(&op->list, &send_list);
0074 spin_unlock(&ops_lock);
0075 wake_up(&send_wq);
0076 }
0077
0078
0079
0080
0081
0082
0083
0084 static void do_unlock_close(const struct dlm_plock_info *info)
0085 {
0086 struct plock_op *op;
0087
0088 op = kzalloc(sizeof(*op), GFP_NOFS);
0089 if (!op)
0090 return;
0091
0092 op->info.optype = DLM_PLOCK_OP_UNLOCK;
0093 op->info.pid = info->pid;
0094 op->info.fsid = info->fsid;
0095 op->info.number = info->number;
0096 op->info.start = 0;
0097 op->info.end = OFFSET_MAX;
0098 op->info.owner = info->owner;
0099
0100 op->info.flags |= DLM_PLOCK_FL_CLOSE;
0101 send_op(op);
0102 }
0103
0104 int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
0105 int cmd, struct file_lock *fl)
0106 {
0107 struct plock_async_data *op_data;
0108 struct dlm_ls *ls;
0109 struct plock_op *op;
0110 int rv;
0111
0112 ls = dlm_find_lockspace_local(lockspace);
0113 if (!ls)
0114 return -EINVAL;
0115
0116 op = kzalloc(sizeof(*op), GFP_NOFS);
0117 if (!op) {
0118 rv = -ENOMEM;
0119 goto out;
0120 }
0121
0122 op->info.optype = DLM_PLOCK_OP_LOCK;
0123 op->info.pid = fl->fl_pid;
0124 op->info.ex = (fl->fl_type == F_WRLCK);
0125 op->info.wait = IS_SETLKW(cmd);
0126 op->info.fsid = ls->ls_global_id;
0127 op->info.number = number;
0128 op->info.start = fl->fl_start;
0129 op->info.end = fl->fl_end;
0130
0131 if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
0132 op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
0133 if (!op_data) {
0134 dlm_release_plock_op(op);
0135 rv = -ENOMEM;
0136 goto out;
0137 }
0138
0139
0140
0141 op->info.owner = (__u64) fl->fl_pid;
0142 op_data->callback = fl->fl_lmops->lm_grant;
0143 locks_init_lock(&op_data->flc);
0144 locks_copy_lock(&op_data->flc, fl);
0145 op_data->fl = fl;
0146 op_data->file = file;
0147
0148 op->data = op_data;
0149
0150 send_op(op);
0151 rv = FILE_LOCK_DEFERRED;
0152 goto out;
0153 } else {
0154 op->info.owner = (__u64)(long) fl->fl_owner;
0155 }
0156
0157 send_op(op);
0158
0159 rv = wait_event_interruptible(recv_wq, (op->done != 0));
0160 if (rv == -ERESTARTSYS) {
0161 spin_lock(&ops_lock);
0162
0163
0164
0165 if (op->done != 0) {
0166 spin_unlock(&ops_lock);
0167 goto do_lock_wait;
0168 }
0169
0170 op->sigint = true;
0171 spin_unlock(&ops_lock);
0172 log_debug(ls, "%s: wait interrupted %x %llx pid %d",
0173 __func__, ls->ls_global_id,
0174 (unsigned long long)number, op->info.pid);
0175 goto out;
0176 }
0177
0178 do_lock_wait:
0179
0180 WARN_ON(!list_empty(&op->list));
0181
0182 rv = op->info.rv;
0183
0184 if (!rv) {
0185 if (locks_lock_file_wait(file, fl) < 0)
0186 log_error(ls, "dlm_posix_lock: vfs lock error %llx",
0187 (unsigned long long)number);
0188 }
0189
0190 dlm_release_plock_op(op);
0191 out:
0192 dlm_put_lockspace(ls);
0193 return rv;
0194 }
0195 EXPORT_SYMBOL_GPL(dlm_posix_lock);
0196
0197
0198 static int dlm_plock_callback(struct plock_op *op)
0199 {
0200 struct plock_async_data *op_data = op->data;
0201 struct file *file;
0202 struct file_lock *fl;
0203 struct file_lock *flc;
0204 int (*notify)(struct file_lock *fl, int result) = NULL;
0205 int rv = 0;
0206
0207 WARN_ON(!list_empty(&op->list));
0208
0209
0210 file = op_data->file;
0211 flc = &op_data->flc;
0212 fl = op_data->fl;
0213 notify = op_data->callback;
0214
0215 if (op->info.rv) {
0216 notify(fl, op->info.rv);
0217 goto out;
0218 }
0219
0220
0221 flc->fl_flags &= ~FL_SLEEP;
0222 if (posix_lock_file(file, flc, NULL)) {
0223
0224
0225
0226
0227
0228
0229
0230
0231 log_print("dlm_plock_callback: vfs lock error %llx file %p fl %p",
0232 (unsigned long long)op->info.number, file, fl);
0233 }
0234
0235 rv = notify(fl, 0);
0236 if (rv) {
0237
0238 log_print("dlm_plock_callback: lock granted after lock request "
0239 "failed; dangling lock!\n");
0240 goto out;
0241 }
0242
0243 out:
0244 dlm_release_plock_op(op);
0245 return rv;
0246 }
0247
0248 int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
0249 struct file_lock *fl)
0250 {
0251 struct dlm_ls *ls;
0252 struct plock_op *op;
0253 int rv;
0254 unsigned char fl_flags = fl->fl_flags;
0255
0256 ls = dlm_find_lockspace_local(lockspace);
0257 if (!ls)
0258 return -EINVAL;
0259
0260 op = kzalloc(sizeof(*op), GFP_NOFS);
0261 if (!op) {
0262 rv = -ENOMEM;
0263 goto out;
0264 }
0265
0266
0267 fl->fl_flags |= FL_EXISTS;
0268
0269 rv = locks_lock_file_wait(file, fl);
0270 if (rv == -ENOENT) {
0271 rv = 0;
0272 goto out_free;
0273 }
0274 if (rv < 0) {
0275 log_error(ls, "dlm_posix_unlock: vfs unlock error %d %llx",
0276 rv, (unsigned long long)number);
0277 }
0278
0279 op->info.optype = DLM_PLOCK_OP_UNLOCK;
0280 op->info.pid = fl->fl_pid;
0281 op->info.fsid = ls->ls_global_id;
0282 op->info.number = number;
0283 op->info.start = fl->fl_start;
0284 op->info.end = fl->fl_end;
0285 if (fl->fl_lmops && fl->fl_lmops->lm_grant)
0286 op->info.owner = (__u64) fl->fl_pid;
0287 else
0288 op->info.owner = (__u64)(long) fl->fl_owner;
0289
0290 if (fl->fl_flags & FL_CLOSE) {
0291 op->info.flags |= DLM_PLOCK_FL_CLOSE;
0292 send_op(op);
0293 rv = 0;
0294 goto out;
0295 }
0296
0297 send_op(op);
0298 wait_event(recv_wq, (op->done != 0));
0299
0300 WARN_ON(!list_empty(&op->list));
0301
0302 rv = op->info.rv;
0303
0304 if (rv == -ENOENT)
0305 rv = 0;
0306
0307 out_free:
0308 dlm_release_plock_op(op);
0309 out:
0310 dlm_put_lockspace(ls);
0311 fl->fl_flags = fl_flags;
0312 return rv;
0313 }
0314 EXPORT_SYMBOL_GPL(dlm_posix_unlock);
0315
0316 int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
0317 struct file_lock *fl)
0318 {
0319 struct dlm_ls *ls;
0320 struct plock_op *op;
0321 int rv;
0322
0323 ls = dlm_find_lockspace_local(lockspace);
0324 if (!ls)
0325 return -EINVAL;
0326
0327 op = kzalloc(sizeof(*op), GFP_NOFS);
0328 if (!op) {
0329 rv = -ENOMEM;
0330 goto out;
0331 }
0332
0333 op->info.optype = DLM_PLOCK_OP_GET;
0334 op->info.pid = fl->fl_pid;
0335 op->info.ex = (fl->fl_type == F_WRLCK);
0336 op->info.fsid = ls->ls_global_id;
0337 op->info.number = number;
0338 op->info.start = fl->fl_start;
0339 op->info.end = fl->fl_end;
0340 if (fl->fl_lmops && fl->fl_lmops->lm_grant)
0341 op->info.owner = (__u64) fl->fl_pid;
0342 else
0343 op->info.owner = (__u64)(long) fl->fl_owner;
0344
0345 send_op(op);
0346 wait_event(recv_wq, (op->done != 0));
0347
0348 WARN_ON(!list_empty(&op->list));
0349
0350
0351
0352
0353 rv = op->info.rv;
0354
0355 fl->fl_type = F_UNLCK;
0356 if (rv == -ENOENT)
0357 rv = 0;
0358 else if (rv > 0) {
0359 locks_init_lock(fl);
0360 fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
0361 fl->fl_flags = FL_POSIX;
0362 fl->fl_pid = -op->info.pid;
0363 fl->fl_start = op->info.start;
0364 fl->fl_end = op->info.end;
0365 rv = 0;
0366 }
0367
0368 dlm_release_plock_op(op);
0369 out:
0370 dlm_put_lockspace(ls);
0371 return rv;
0372 }
0373 EXPORT_SYMBOL_GPL(dlm_posix_get);
0374
0375
0376 static ssize_t dev_read(struct file *file, char __user *u, size_t count,
0377 loff_t *ppos)
0378 {
0379 struct dlm_plock_info info;
0380 struct plock_op *op = NULL;
0381
0382 if (count < sizeof(info))
0383 return -EINVAL;
0384
0385 spin_lock(&ops_lock);
0386 if (!list_empty(&send_list)) {
0387 op = list_first_entry(&send_list, struct plock_op, list);
0388 if (op->info.flags & DLM_PLOCK_FL_CLOSE)
0389 list_del(&op->list);
0390 else
0391 list_move(&op->list, &recv_list);
0392 memcpy(&info, &op->info, sizeof(info));
0393 }
0394 spin_unlock(&ops_lock);
0395
0396 if (!op)
0397 return -EAGAIN;
0398
0399
0400
0401
0402
0403 if (op->info.flags & DLM_PLOCK_FL_CLOSE)
0404 dlm_release_plock_op(op);
0405
0406 if (copy_to_user(u, &info, sizeof(info)))
0407 return -EFAULT;
0408 return sizeof(info);
0409 }
0410
0411
0412
0413 static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
0414 loff_t *ppos)
0415 {
0416 struct plock_op *op = NULL, *iter;
0417 struct dlm_plock_info info;
0418 int do_callback = 0;
0419
0420 if (count != sizeof(info))
0421 return -EINVAL;
0422
0423 if (copy_from_user(&info, u, sizeof(info)))
0424 return -EFAULT;
0425
0426 if (check_version(&info))
0427 return -EINVAL;
0428
0429 spin_lock(&ops_lock);
0430 list_for_each_entry(iter, &recv_list, list) {
0431 if (iter->info.fsid == info.fsid &&
0432 iter->info.number == info.number &&
0433 iter->info.owner == info.owner) {
0434 if (iter->sigint) {
0435 list_del(&iter->list);
0436 spin_unlock(&ops_lock);
0437
0438 pr_debug("%s: sigint cleanup %x %llx pid %d",
0439 __func__, iter->info.fsid,
0440 (unsigned long long)iter->info.number,
0441 iter->info.pid);
0442 do_unlock_close(&iter->info);
0443 memcpy(&iter->info, &info, sizeof(info));
0444 dlm_release_plock_op(iter);
0445 return count;
0446 }
0447 list_del_init(&iter->list);
0448 memcpy(&iter->info, &info, sizeof(info));
0449 if (iter->data)
0450 do_callback = 1;
0451 else
0452 iter->done = 1;
0453 op = iter;
0454 break;
0455 }
0456 }
0457 spin_unlock(&ops_lock);
0458
0459 if (op) {
0460 if (do_callback)
0461 dlm_plock_callback(op);
0462 else
0463 wake_up(&recv_wq);
0464 } else
0465 log_print("%s: no op %x %llx", __func__,
0466 info.fsid, (unsigned long long)info.number);
0467 return count;
0468 }
0469
0470 static __poll_t dev_poll(struct file *file, poll_table *wait)
0471 {
0472 __poll_t mask = 0;
0473
0474 poll_wait(file, &send_wq, wait);
0475
0476 spin_lock(&ops_lock);
0477 if (!list_empty(&send_list))
0478 mask = EPOLLIN | EPOLLRDNORM;
0479 spin_unlock(&ops_lock);
0480
0481 return mask;
0482 }
0483
0484 static const struct file_operations dev_fops = {
0485 .read = dev_read,
0486 .write = dev_write,
0487 .poll = dev_poll,
0488 .owner = THIS_MODULE,
0489 .llseek = noop_llseek,
0490 };
0491
0492 static struct miscdevice plock_dev_misc = {
0493 .minor = MISC_DYNAMIC_MINOR,
0494 .name = DLM_PLOCK_MISC_NAME,
0495 .fops = &dev_fops
0496 };
0497
0498 int dlm_plock_init(void)
0499 {
0500 int rv;
0501
0502 rv = misc_register(&plock_dev_misc);
0503 if (rv)
0504 log_print("dlm_plock_init: misc_register failed %d", rv);
0505 return rv;
0506 }
0507
0508 void dlm_plock_exit(void)
0509 {
0510 misc_deregister(&plock_dev_misc);
0511 }
0512