1/* 2 * Copyright (C) 2005 Red Hat, Inc. All rights reserved. 3 * 4 * This copyrighted material is made available to anyone wishing to use, 5 * modify, copy, or redistribute it subject to the terms and conditions 6 * of the GNU General Public License version 2. 7 */ 8 9#include <linux/miscdevice.h> 10#include <linux/lock_dlm_plock.h> 11#include <linux/poll.h> 12 13#include "lock_dlm.h" 14 15 16static spinlock_t ops_lock; 17static struct list_head send_list; 18static struct list_head recv_list; 19static wait_queue_head_t send_wq; 20static wait_queue_head_t recv_wq; 21 22struct plock_op { 23 struct list_head list; 24 int done; 25 struct gdlm_plock_info info; 26}; 27 28struct plock_xop { 29 struct plock_op xop; 30 void *callback; 31 void *fl; 32 void *file; 33 struct file_lock flc; 34}; 35 36 37static inline void set_version(struct gdlm_plock_info *info) 38{ 39 info->version[0] = GDLM_PLOCK_VERSION_MAJOR; 40 info->version[1] = GDLM_PLOCK_VERSION_MINOR; 41 info->version[2] = GDLM_PLOCK_VERSION_PATCH; 42} 43 44static int check_version(struct gdlm_plock_info *info) 45{ 46 if ((GDLM_PLOCK_VERSION_MAJOR != info->version[0]) || 47 (GDLM_PLOCK_VERSION_MINOR < info->version[1])) { 48 log_error("plock device version mismatch: " 49 "kernel (%u.%u.%u), user (%u.%u.%u)", 50 GDLM_PLOCK_VERSION_MAJOR, 51 GDLM_PLOCK_VERSION_MINOR, 52 GDLM_PLOCK_VERSION_PATCH, 53 info->version[0], 54 info->version[1], 55 info->version[2]); 56 return -EINVAL; 57 } 58 return 0; 59} 60 61static void send_op(struct plock_op *op) 62{ 63 set_version(&op->info); 64 INIT_LIST_HEAD(&op->list); 65 spin_lock(&ops_lock); 66 list_add_tail(&op->list, &send_list); 67 spin_unlock(&ops_lock); 68 wake_up(&send_wq); 69} 70 71int gdlm_plock(void *lockspace, struct lm_lockname *name, 72 struct file *file, int cmd, struct file_lock *fl) 73{ 74 struct gdlm_ls *ls = lockspace; 75 struct plock_op *op; 76 struct plock_xop *xop; 77 int rv; 78 79 xop = kzalloc(sizeof(*xop), GFP_KERNEL); 80 if (!xop) 81 return -ENOMEM; 82 83 op = &xop->xop; 84 op->info.optype = GDLM_PLOCK_OP_LOCK; 85 op->info.pid = fl->fl_pid; 86 op->info.ex = (fl->fl_type == F_WRLCK); 87 op->info.wait = IS_SETLKW(cmd); 88 op->info.fsid = ls->id; 89 op->info.number = name->ln_number; 90 op->info.start = fl->fl_start; 91 op->info.end = fl->fl_end; 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; 101 102 send_op(op); 103 104 if (xop->callback == NULL) 105 wait_event(recv_wq, (op->done != 0)); 106 else 107 return -EINPROGRESS; 108 109 spin_lock(&ops_lock); 110 if (!list_empty(&op->list)) { 111 printk(KERN_INFO "plock op on list\n"); 112 list_del(&op->list); 113 } 114 spin_unlock(&ops_lock); 115 116 rv = op->info.rv; 117 118 if (!rv) { 119 if (posix_lock_file_wait(file, fl) < 0) 120 log_error("gdlm_plock: vfs lock error %x,%llx", 121 name->ln_type, 122 (unsigned long long)name->ln_number); 123 } 124 125 kfree(xop); 126 return rv; 127} 128 129/* Returns failure iff a succesful lock operation should be canceled */ 130static 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 printk("gfs2 lock granted after lock request failed;" 175 " dangling lock!\n"); 176 goto out; 177 } 178 179out: 180 kfree(xop); 181 return rv; 182} 183 184int gdlm_punlock(void *lockspace, struct lm_lockname *name, 185 struct file *file, struct file_lock *fl) 186{ 187 struct gdlm_ls *ls = lockspace; 188 struct plock_op *op; 189 int rv; 190 191 op = kzalloc(sizeof(*op), GFP_KERNEL); 192 if (!op) 193 return -ENOMEM; 194 195 if (posix_lock_file_wait(file, fl) < 0) 196 log_error("gdlm_punlock: vfs unlock error %x,%llx", 197 name->ln_type, (unsigned long long)name->ln_number); 198 199 op->info.optype = GDLM_PLOCK_OP_UNLOCK; 200 op->info.pid = fl->fl_pid; 201 op->info.fsid = ls->id; 202 op->info.number = name->ln_number; 203 op->info.start = fl->fl_start; 204 op->info.end = fl->fl_end; 205 op->info.owner = (__u64)(long) fl->fl_owner; 206 207 send_op(op); 208 wait_event(recv_wq, (op->done != 0)); 209 210 spin_lock(&ops_lock); 211 if (!list_empty(&op->list)) { 212 printk(KERN_INFO "punlock op on list\n"); 213 list_del(&op->list); 214 } 215 spin_unlock(&ops_lock); 216 217 rv = op->info.rv; 218 219 if (rv == -ENOENT) 220 rv = 0; 221 222 kfree(op); 223 return rv; 224} 225 226int gdlm_plock_get(void *lockspace, struct lm_lockname *name, 227 struct file *file, struct file_lock *fl) 228{ 229 struct gdlm_ls *ls = lockspace; 230 struct plock_op *op; 231 int rv; 232 233 op = kzalloc(sizeof(*op), GFP_KERNEL); 234 if (!op) 235 return -ENOMEM; 236 237 op->info.optype = GDLM_PLOCK_OP_GET; 238 op->info.pid = fl->fl_pid; 239 op->info.ex = (fl->fl_type == F_WRLCK); 240 op->info.fsid = ls->id; 241 op->info.number = name->ln_number; 242 op->info.start = fl->fl_start; 243 op->info.end = fl->fl_end; 244 245 246 send_op(op); 247 wait_event(recv_wq, (op->done != 0)); 248 249 spin_lock(&ops_lock); 250 if (!list_empty(&op->list)) { 251 printk(KERN_INFO "plock_get op on list\n"); 252 list_del(&op->list); 253 } 254 spin_unlock(&ops_lock); 255 256 rv = op->info.rv; 257 258 fl->fl_type = F_UNLCK; 259 if (rv == -ENOENT) 260 rv = 0; 261 else if (rv == 0 && op->info.pid != fl->fl_pid) { 262 fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK; 263 fl->fl_pid = op->info.pid; 264 fl->fl_start = op->info.start; 265 fl->fl_end = op->info.end; 266 } 267 268 kfree(op); 269 return rv; 270} 271 272/* a read copies out one plock request from the send list */ 273static ssize_t dev_read(struct file *file, char __user *u, size_t count, 274 loff_t *ppos) 275{ 276 struct gdlm_plock_info info; 277 struct plock_op *op = NULL; 278 279 if (count < sizeof(info)) 280 return -EINVAL; 281 282 spin_lock(&ops_lock); 283 if (!list_empty(&send_list)) { 284 op = list_entry(send_list.next, struct plock_op, list); 285 list_move(&op->list, &recv_list); 286 memcpy(&info, &op->info, sizeof(info)); 287 } 288 spin_unlock(&ops_lock); 289 290 if (!op) 291 return -EAGAIN; 292 293 if (copy_to_user(u, &info, sizeof(info))) 294 return -EFAULT; 295 return sizeof(info); 296} 297 298/* a write copies in one plock result that should match a plock_op 299 on the recv list */ 300static ssize_t dev_write(struct file *file, const char __user *u, size_t count, 301 loff_t *ppos) 302{ 303 struct gdlm_plock_info info; 304 struct plock_op *op; 305 int found = 0; 306 307 if (count != sizeof(info)) 308 return -EINVAL; 309 310 if (copy_from_user(&info, u, sizeof(info))) 311 return -EFAULT; 312 313 if (check_version(&info)) 314 return -EINVAL; 315 316 spin_lock(&ops_lock); 317 list_for_each_entry(op, &recv_list, list) { 318 if (op->info.fsid == info.fsid && op->info.number == info.number && 319 op->info.owner == info.owner) { 320 list_del_init(&op->list); 321 found = 1; 322 op->done = 1; 323 memcpy(&op->info, &info, sizeof(info)); 324 break; 325 } 326 } 327 spin_unlock(&ops_lock); 328 329 if (found) { 330 struct plock_xop *xop; 331 xop = (struct plock_xop *)op; 332 if (xop->callback) 333 count = gdlm_plock_callback(op); 334 else 335 wake_up(&recv_wq); 336 } else 337 printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid, 338 (unsigned long long)info.number); 339 return count; 340} 341 342static unsigned int dev_poll(struct file *file, poll_table *wait) 343{ 344 poll_wait(file, &send_wq, wait); 345 346 spin_lock(&ops_lock); 347 if (!list_empty(&send_list)) { 348 spin_unlock(&ops_lock); 349 return POLLIN | POLLRDNORM; 350 } 351 spin_unlock(&ops_lock); 352 return 0; 353} 354 355static const struct file_operations dev_fops = { 356 .read = dev_read, 357 .write = dev_write, 358 .poll = dev_poll, 359 .owner = THIS_MODULE 360}; 361 362static struct miscdevice plock_dev_misc = { 363 .minor = MISC_DYNAMIC_MINOR, 364 .name = GDLM_PLOCK_MISC_NAME, 365 .fops = &dev_fops 366}; 367 368int gdlm_plock_init(void) 369{ 370 int rv; 371 372 spin_lock_init(&ops_lock); 373 INIT_LIST_HEAD(&send_list); 374 INIT_LIST_HEAD(&recv_list); 375 init_waitqueue_head(&send_wq); 376 init_waitqueue_head(&recv_wq); 377 378 rv = misc_register(&plock_dev_misc); 379 if (rv) 380 printk(KERN_INFO "gdlm_plock_init: misc_register failed %d", 381 rv); 382 return rv; 383} 384 385void gdlm_plock_exit(void) 386{ 387 if (misc_deregister(&plock_dev_misc) < 0) 388 printk(KERN_INFO "gdlm_plock_exit: misc_deregister failed"); 389} 390