| 1 | |
| 2 | |
| 3 | * Copyright (C) 2006-2010 Red Hat, Inc. All rights reserved.
|
| 4 |
|
| 5 |
|
| 6 | #include <linux/miscdevice.h>
|
| 7 | #include <linux/capability.h>
|
| 8 | #include <linux/init.h>
|
| 9 | #include <linux/wait.h>
|
| 10 | #include <linux/file.h>
|
| 11 | #include <linux/fs.h>
|
| 12 | #include <linux/poll.h>
|
| 13 | #include <linux/signal.h>
|
| 14 | #include <linux/spinlock.h>
|
| 15 | #include <linux/dlm.h>
|
| 16 | #include <linux/dlm_device.h>
|
| 17 | #include <linux/slab.h>
|
| 18 | #include <linux/sched/signal.h>
|
| 19 |
|
| 20 | #include <trace/events/dlm.h>
|
| 21 |
|
| 22 | #include "dlm_internal.h"
|
| 23 | #include "lockspace.h"
|
| 24 | #include "lock.h"
|
| 25 | #include "lvb_table.h"
|
| 26 | #include "user.h"
|
| 27 | #include "ast.h"
|
| 28 | #include "config.h"
|
| 29 | #include "memory.h"
|
| 30 |
|
| 31 | static const char name_prefix[] = "dlm";
|
| 32 | static const struct file_operations device_fops;
|
| 33 | static atomic_t dlm_monitor_opened;
|
| 34 | static int dlm_monitor_unused = 1;
|
| 35 |
|
| 36 | #ifdef CONFIG_COMPAT
|
| 37 |
|
| 38 | struct dlm_lock_params32 {
|
| 39 | __u8 mode;
|
| 40 | __u8 namelen;
|
| 41 | __u16 unused;
|
| 42 | __u32 flags;
|
| 43 | __u32 lkid;
|
| 44 | __u32 parent;
|
| 45 | __u64 xid;
|
| 46 | __u64 timeout;
|
| 47 | __u32 castparam;
|
| 48 | __u32 castaddr;
|
| 49 | __u32 bastparam;
|
| 50 | __u32 bastaddr;
|
| 51 | __u32 lksb;
|
| 52 | char lvb[DLM_USER_LVB_LEN];
|
| 53 | char name[];
|
| 54 | };
|
| 55 |
|
| 56 | struct dlm_write_request32 {
|
| 57 | __u32 version[3];
|
| 58 | __u8 cmd;
|
| 59 | __u8 is64bit;
|
| 60 | __u8 unused[2];
|
| 61 |
|
| 62 | union {
|
| 63 | struct dlm_lock_params32 lock;
|
| 64 | struct dlm_lspace_params lspace;
|
| 65 | struct dlm_purge_params purge;
|
| 66 | } i;
|
| 67 | };
|
| 68 |
|
| 69 | struct dlm_lksb32 {
|
| 70 | __u32 sb_status;
|
| 71 | __u32 sb_lkid;
|
| 72 | __u8 sb_flags;
|
| 73 | __u32 sb_lvbptr;
|
| 74 | };
|
| 75 |
|
| 76 | struct dlm_lock_result32 {
|
| 77 | __u32 version[3];
|
| 78 | __u32 length;
|
| 79 | __u32 user_astaddr;
|
| 80 | __u32 user_astparam;
|
| 81 | __u32 user_lksb;
|
| 82 | struct dlm_lksb32 lksb;
|
| 83 | __u8 bast_mode;
|
| 84 | __u8 unused[3];
|
| 85 |
|
| 86 | __u32 lvb_offset;
|
| 87 | };
|
| 88 |
|
| 89 | static void compat_input(struct dlm_write_request *kb,
|
| 90 | struct dlm_write_request32 *kb32,
|
| 91 | int namelen)
|
| 92 | {
|
| 93 | kb->version[0] = kb32->version[0];
|
| 94 | kb->version[1] = kb32->version[1];
|
| 95 | kb->version[2] = kb32->version[2];
|
| 96 |
|
| 97 | kb->cmd = kb32->cmd;
|
| 98 | kb->is64bit = kb32->is64bit;
|
| 99 | if (kb->cmd == DLM_USER_CREATE_LOCKSPACE ||
|
| 100 | kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {
|
| 101 | kb->i.lspace.flags = kb32->i.lspace.flags;
|
| 102 | kb->i.lspace.minor = kb32->i.lspace.minor;
|
| 103 | memcpy(kb->i.lspace.name, kb32->i.lspace.name, namelen);
|
| 104 | } else if (kb->cmd == DLM_USER_PURGE) {
|
| 105 | kb->i.purge.nodeid = kb32->i.purge.nodeid;
|
| 106 | kb->i.purge.pid = kb32->i.purge.pid;
|
| 107 | } else {
|
| 108 | kb->i.lock.mode = kb32->i.lock.mode;
|
| 109 | kb->i.lock.namelen = kb32->i.lock.namelen;
|
| 110 | kb->i.lock.flags = kb32->i.lock.flags;
|
| 111 | kb->i.lock.lkid = kb32->i.lock.lkid;
|
| 112 | kb->i.lock.parent = kb32->i.lock.parent;
|
| 113 | kb->i.lock.xid = kb32->i.lock.xid;
|
| 114 | kb->i.lock.timeout = kb32->i.lock.timeout;
|
| 115 | kb->i.lock.castparam = (__user void *)(long)kb32->i.lock.castparam;
|
| 116 | kb->i.lock.castaddr = (__user void *)(long)kb32->i.lock.castaddr;
|
| 117 | kb->i.lock.bastparam = (__user void *)(long)kb32->i.lock.bastparam;
|
| 118 | kb->i.lock.bastaddr = (__user void *)(long)kb32->i.lock.bastaddr;
|
| 119 | kb->i.lock.lksb = (__user void *)(long)kb32->i.lock.lksb;
|
| 120 | memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);
|
| 121 | memcpy(kb->i.lock.name, kb32->i.lock.name, namelen);
|
| 122 | }
|
| 123 | }
|
| 124 |
|
| 125 | static void compat_output(struct dlm_lock_result *res,
|
| 126 | struct dlm_lock_result32 *res32)
|
| 127 | {
|
| 128 | memset(res32, 0, sizeof(*res32));
|
| 129 |
|
| 130 | res32->version[0] = res->version[0];
|
| 131 | res32->version[1] = res->version[1];
|
| 132 | res32->version[2] = res->version[2];
|
| 133 |
|
| 134 | res32->user_astaddr = (__u32)(__force long)res->user_astaddr;
|
| 135 | res32->user_astparam = (__u32)(__force long)res->user_astparam;
|
| 136 | res32->user_lksb = (__u32)(__force long)res->user_lksb;
|
| 137 | res32->bast_mode = res->bast_mode;
|
| 138 |
|
| 139 | res32->lvb_offset = res->lvb_offset;
|
| 140 | res32->length = res->length;
|
| 141 |
|
| 142 | res32->lksb.sb_status = res->lksb.sb_status;
|
| 143 | res32->lksb.sb_flags = res->lksb.sb_flags;
|
| 144 | res32->lksb.sb_lkid = res->lksb.sb_lkid;
|
| 145 | res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr;
|
| 146 | }
|
| 147 | #endif
|
| 148 |
|
| 149 | |
| 150 | available for the application to use. The lkb still exists until
|
| 151 | the final ast is read. A lock becomes EOL in three situations:
|
| 152 | 1. a noqueue request fails with EAGAIN
|
| 153 | 2. an unlock completes with EUNLOCK
|
| 154 | 3. a cancel of a waiting request completes with ECANCEL/EDEADLK
|
| 155 | An EOL lock needs to be removed from the process's list of locks.
|
| 156 | And we can't allow any new operation on an EOL lock. This is
|
| 157 | not related to the lifetime of the lkb struct which is managed
|
| 158 | entirely by refcount.
|
| 159 |
|
| 160 | static int lkb_is_endoflife(int mode, int status)
|
| 161 | {
|
| 162 | switch (status) {
|
| 163 | case -DLM_EUNLOCK:
|
| 164 | return 1;
|
| 165 | case -DLM_ECANCEL:
|
| 166 | case -ETIMEDOUT:
|
| 167 | case -EDEADLK:
|
| 168 | case -EAGAIN:
|
| 169 | if (mode == DLM_LOCK_IV)
|
| 170 | return 1;
|
| 171 | break;
|
| 172 | }
|
| 173 | return 0;
|
| 174 | }
|
| 175 |
|
| 176 | |
| 177 | being removed and then remove that lkb from the orphans list and free it
|
| 178 |
|
| 179 | void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
|
| 180 | int status, uint32_t sbflags)
|
| 181 | {
|
| 182 | struct dlm_ls *ls;
|
| 183 | struct dlm_user_args *ua;
|
| 184 | struct dlm_user_proc *proc;
|
| 185 | struct dlm_callback *cb;
|
| 186 | int rv, copy_lvb;
|
| 187 |
|
| 188 | if (test_bit(DLM_DFL_ORPHAN_BIT, &lkb->lkb_dflags) ||
|
| 189 | test_bit(DLM_IFL_DEAD_BIT, &lkb->lkb_iflags))
|
| 190 | return;
|
| 191 |
|
| 192 | ls = lkb->lkb_resource->res_ls;
|
| 193 | spin_lock_bh(&ls->ls_clear_proc_locks);
|
| 194 |
|
| 195 | |
| 196 | can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed
|
| 197 | lkb->ua so we can't try to use it. This second check is necessary
|
| 198 | for cases where a completion ast is received for an operation that
|
| 199 | began before clear_proc_locks did its cancel/unlock.
|
| 200 |
|
| 201 | if (test_bit(DLM_DFL_ORPHAN_BIT, &lkb->lkb_dflags) ||
|
| 202 | test_bit(DLM_IFL_DEAD_BIT, &lkb->lkb_iflags))
|
| 203 | goto out;
|
| 204 |
|
| 205 | DLM_ASSERT(lkb->lkb_ua, dlm_print_lkb(lkb););
|
| 206 | ua = lkb->lkb_ua;
|
| 207 | proc = ua->proc;
|
| 208 |
|
| 209 | if ((flags & DLM_CB_BAST) && ua->bastaddr == NULL)
|
| 210 | goto out;
|
| 211 |
|
| 212 | if ((flags & DLM_CB_CAST) && lkb_is_endoflife(mode, status))
|
| 213 | set_bit(DLM_IFL_ENDOFLIFE_BIT, &lkb->lkb_iflags);
|
| 214 |
|
| 215 | spin_lock_bh(&proc->asts_spin);
|
| 216 |
|
| 217 | if (!dlm_may_skip_callback(lkb, flags, mode, status, sbflags,
|
| 218 | ©_lvb)) {
|
| 219 | rv = dlm_get_cb(lkb, flags, mode, status, sbflags, &cb);
|
| 220 | if (!rv) {
|
| 221 | cb->copy_lvb = copy_lvb;
|
| 222 | cb->ua = *ua;
|
| 223 | cb->lkb_lksb = &cb->ua.lksb;
|
| 224 | if (copy_lvb) {
|
| 225 | memcpy(cb->lvbptr, ua->lksb.sb_lvbptr,
|
| 226 | DLM_USER_LVB_LEN);
|
| 227 | cb->lkb_lksb->sb_lvbptr = cb->lvbptr;
|
| 228 | }
|
| 229 |
|
| 230 | list_add_tail(&cb->list, &proc->asts);
|
| 231 | wake_up_interruptible(&proc->wait);
|
| 232 | }
|
| 233 | }
|
| 234 | spin_unlock_bh(&proc->asts_spin);
|
| 235 |
|
| 236 | if (test_bit(DLM_IFL_ENDOFLIFE_BIT, &lkb->lkb_iflags)) {
|
| 237 |
|
| 238 | spin_lock_bh(&proc->locks_spin);
|
| 239 | if (!list_empty(&lkb->lkb_ownqueue)) {
|
| 240 | list_del_init(&lkb->lkb_ownqueue);
|
| 241 | dlm_put_lkb(lkb);
|
| 242 | }
|
| 243 | spin_unlock_bh(&proc->locks_spin);
|
| 244 | }
|
| 245 | out:
|
| 246 | spin_unlock_bh(&ls->ls_clear_proc_locks);
|
| 247 | }
|
| 248 |
|
| 249 | static int device_user_lock(struct dlm_user_proc *proc,
|
| 250 | struct dlm_lock_params *params)
|
| 251 | {
|
| 252 | struct dlm_ls *ls;
|
| 253 | struct dlm_user_args *ua;
|
| 254 | uint32_t lkid;
|
| 255 | int error = -ENOMEM;
|
| 256 |
|
| 257 | ls = dlm_find_lockspace_local(proc->lockspace);
|
| 258 | if (!ls)
|
| 259 | return -ENOENT;
|
| 260 |
|
| 261 | if (!params->castaddr || !params->lksb) {
|
| 262 | error = -EINVAL;
|
| 263 | goto out;
|
| 264 | }
|
| 265 |
|
| 266 | ua = kzalloc_obj(struct dlm_user_args, GFP_NOFS);
|
| 267 | if (!ua)
|
| 268 | goto out;
|
| 269 | ua->proc = proc;
|
| 270 | ua->user_lksb = params->lksb;
|
| 271 | ua->castparam = params->castparam;
|
| 272 | ua->castaddr = params->castaddr;
|
| 273 | ua->bastparam = params->bastparam;
|
| 274 | ua->bastaddr = params->bastaddr;
|
| 275 | ua->xid = params->xid;
|
| 276 |
|
| 277 | if (params->flags & DLM_LKF_CONVERT) {
|
| 278 | error = dlm_user_convert(ls, ua,
|
| 279 | params->mode, params->flags,
|
| 280 | params->lkid, params->lvb);
|
| 281 | } else if (params->flags & DLM_LKF_ORPHAN) {
|
| 282 | error = dlm_user_adopt_orphan(ls, ua,
|
| 283 | params->mode, params->flags,
|
| 284 | params->name, params->namelen,
|
| 285 | &lkid);
|
| 286 | if (!error)
|
| 287 | error = lkid;
|
| 288 | } else {
|
| 289 | error = dlm_user_request(ls, ua,
|
| 290 | params->mode, params->flags,
|
| 291 | params->name, params->namelen);
|
| 292 | if (!error)
|
| 293 | error = ua->lksb.sb_lkid;
|
| 294 | }
|
| 295 | out:
|
| 296 | dlm_put_lockspace(ls);
|
| 297 | return error;
|
| 298 | }
|
| 299 |
|
| 300 | static int device_user_unlock(struct dlm_user_proc *proc,
|
| 301 | struct dlm_lock_params *params)
|
| 302 | {
|
| 303 | struct dlm_ls *ls;
|
| 304 | struct dlm_user_args *ua;
|
| 305 | int error = -ENOMEM;
|
| 306 |
|
| 307 | ls = dlm_find_lockspace_local(proc->lockspace);
|
| 308 | if (!ls)
|
| 309 | return -ENOENT;
|
| 310 |
|
| 311 | ua = kzalloc_obj(struct dlm_user_args, GFP_NOFS);
|
| 312 | if (!ua)
|
| 313 | goto out;
|
| 314 | ua->proc = proc;
|
| 315 | ua->user_lksb = params->lksb;
|
| 316 | ua->castparam = params->castparam;
|
| 317 | ua->castaddr = params->castaddr;
|
| 318 |
|
| 319 | if (params->flags & DLM_LKF_CANCEL)
|
| 320 | error = dlm_user_cancel(ls, ua, params->flags, params->lkid);
|
| 321 | else
|
| 322 | error = dlm_user_unlock(ls, ua, params->flags, params->lkid,
|
| 323 | params->lvb);
|
| 324 | out:
|
| 325 | dlm_put_lockspace(ls);
|
| 326 | return error;
|
| 327 | }
|
| 328 |
|
| 329 | static int device_user_deadlock(struct dlm_user_proc *proc,
|
| 330 | struct dlm_lock_params *params)
|
| 331 | {
|
| 332 | struct dlm_ls *ls;
|
| 333 | int error;
|
| 334 |
|
| 335 | ls = dlm_find_lockspace_local(proc->lockspace);
|
| 336 | if (!ls)
|
| 337 | return -ENOENT;
|
| 338 |
|
| 339 | error = dlm_user_deadlock(ls, params->flags, params->lkid);
|
| 340 |
|
| 341 | dlm_put_lockspace(ls);
|
| 342 | return error;
|
| 343 | }
|
| 344 |
|
| 345 | static int dlm_device_register(struct dlm_ls *ls, char *name)
|
| 346 | {
|
| 347 | int error, len;
|
| 348 |
|
| 349 | |
| 350 | lockspace is created multiple times from userspace.
|
| 351 | if (ls->ls_device.name)
|
| 352 | return 0;
|
| 353 |
|
| 354 | error = -ENOMEM;
|
| 355 | len = strlen(name) + strlen(name_prefix) + 2;
|
| 356 | ls->ls_device.name = kzalloc(len, GFP_NOFS);
|
| 357 | if (!ls->ls_device.name)
|
| 358 | goto fail;
|
| 359 |
|
| 360 | snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
|
| 361 | name);
|
| 362 | ls->ls_device.fops = &device_fops;
|
| 363 | ls->ls_device.minor = MISC_DYNAMIC_MINOR;
|
| 364 |
|
| 365 | error = misc_register(&ls->ls_device);
|
| 366 | if (error) {
|
| 367 | kfree(ls->ls_device.name);
|
| 368 | |
| 369 | * to avoid a double-free in dlm_device_deregister
|
| 370 |
|
| 371 | ls->ls_device.name = NULL;
|
| 372 | }
|
| 373 | fail:
|
| 374 | return error;
|
| 375 | }
|
| 376 |
|
| 377 | int dlm_device_deregister(struct dlm_ls *ls)
|
| 378 | {
|
| 379 | |
| 380 | was never used from userspace, or when device_create_lockspace()
|
| 381 | calls dlm_release_lockspace() after the register fails.
|
| 382 | if (!ls->ls_device.name)
|
| 383 | return 0;
|
| 384 |
|
| 385 | misc_deregister(&ls->ls_device);
|
| 386 | kfree(ls->ls_device.name);
|
| 387 | return 0;
|
| 388 | }
|
| 389 |
|
| 390 | static int device_user_purge(struct dlm_user_proc *proc,
|
| 391 | struct dlm_purge_params *params)
|
| 392 | {
|
| 393 | struct dlm_ls *ls;
|
| 394 | int error;
|
| 395 |
|
| 396 | ls = dlm_find_lockspace_local(proc->lockspace);
|
| 397 | if (!ls)
|
| 398 | return -ENOENT;
|
| 399 |
|
| 400 | error = dlm_user_purge(ls, proc, params->nodeid, params->pid);
|
| 401 |
|
| 402 | dlm_put_lockspace(ls);
|
| 403 | return error;
|
| 404 | }
|
| 405 |
|
| 406 | static int device_create_lockspace(struct dlm_lspace_params *params)
|
| 407 | {
|
| 408 | dlm_lockspace_t *lockspace;
|
| 409 | struct dlm_ls *ls;
|
| 410 | int error;
|
| 411 |
|
| 412 | if (!capable(CAP_SYS_ADMIN))
|
| 413 | return -EPERM;
|
| 414 |
|
| 415 | error = dlm_new_user_lockspace(params->name, dlm_config.ci_cluster_name,
|
| 416 | params->flags, DLM_USER_LVB_LEN, NULL,
|
| 417 | NULL, NULL, &lockspace);
|
| 418 | if (error)
|
| 419 | return error;
|
| 420 |
|
| 421 | ls = dlm_find_lockspace_local(lockspace);
|
| 422 | if (!ls)
|
| 423 | return -ENOENT;
|
| 424 |
|
| 425 | error = dlm_device_register(ls, params->name);
|
| 426 | dlm_put_lockspace(ls);
|
| 427 |
|
| 428 | if (error)
|
| 429 | dlm_release_lockspace(lockspace, DLM_RELEASE_NO_LOCKS);
|
| 430 | else
|
| 431 | error = ls->ls_device.minor;
|
| 432 |
|
| 433 | return error;
|
| 434 | }
|
| 435 |
|
| 436 | static int device_remove_lockspace(struct dlm_lspace_params *params)
|
| 437 | {
|
| 438 | dlm_lockspace_t *lockspace;
|
| 439 | struct dlm_ls *ls;
|
| 440 | int error, force = DLM_RELEASE_NO_LOCKS;
|
| 441 |
|
| 442 | if (!capable(CAP_SYS_ADMIN))
|
| 443 | return -EPERM;
|
| 444 |
|
| 445 | ls = dlm_find_lockspace_device(params->minor);
|
| 446 | if (!ls)
|
| 447 | return -ENOENT;
|
| 448 |
|
| 449 | if (params->flags & DLM_USER_LSFLG_FORCEFREE)
|
| 450 | force = DLM_RELEASE_NORMAL;
|
| 451 |
|
| 452 | lockspace = ls;
|
| 453 | dlm_put_lockspace(ls);
|
| 454 |
|
| 455 | |
| 456 | zero, so all processes will need to close their device for the
|
| 457 | ls before the release will proceed. release also calls the
|
| 458 | device_deregister above. Converting a positive return value
|
| 459 | from release to zero means that userspace won't know when its
|
| 460 | release was the final one, but it shouldn't need to know.
|
| 461 |
|
| 462 | error = dlm_release_lockspace(lockspace, force);
|
| 463 | if (error > 0)
|
| 464 | error = 0;
|
| 465 | return error;
|
| 466 | }
|
| 467 |
|
| 468 |
|
| 469 | static int check_version(struct dlm_write_request *req)
|
| 470 | {
|
| 471 | if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||
|
| 472 | (req->version[0] == DLM_DEVICE_VERSION_MAJOR &&
|
| 473 | req->version[1] > DLM_DEVICE_VERSION_MINOR)) {
|
| 474 |
|
| 475 | printk(KERN_DEBUG "dlm: process %s (%d) version mismatch "
|
| 476 | "user (%d.%d.%d) kernel (%d.%d.%d)\n",
|
| 477 | current->comm,
|
| 478 | task_pid_nr(current),
|
| 479 | req->version[0],
|
| 480 | req->version[1],
|
| 481 | req->version[2],
|
| 482 | DLM_DEVICE_VERSION_MAJOR,
|
| 483 | DLM_DEVICE_VERSION_MINOR,
|
| 484 | DLM_DEVICE_VERSION_PATCH);
|
| 485 | return -EINVAL;
|
| 486 | }
|
| 487 | return 0;
|
| 488 | }
|
| 489 |
|
| 490 | |
| 491 | * device_write
|
| 492 | *
|
| 493 | * device_user_lock
|
| 494 | * dlm_user_request -> request_lock
|
| 495 | * dlm_user_convert -> convert_lock
|
| 496 | *
|
| 497 | * device_user_unlock
|
| 498 | * dlm_user_unlock -> unlock_lock
|
| 499 | * dlm_user_cancel -> cancel_lock
|
| 500 | *
|
| 501 | * device_create_lockspace
|
| 502 | * dlm_new_lockspace
|
| 503 | *
|
| 504 | * device_remove_lockspace
|
| 505 | * dlm_release_lockspace
|
| 506 |
|
| 507 |
|
| 508 | |
| 509 | to the control device is to create/remove a lockspace
|
| 510 |
|
| 511 | static ssize_t device_write(struct file *file, const char __user *buf,
|
| 512 | size_t count, loff_t *ppos)
|
| 513 | {
|
| 514 | struct dlm_user_proc *proc = file->private_data;
|
| 515 | size_t name_payload = 0;
|
| 516 | struct dlm_write_request *kbuf;
|
| 517 | int error;
|
| 518 |
|
| 519 | #ifdef CONFIG_COMPAT
|
| 520 | if (count < sizeof(struct dlm_write_request32))
|
| 521 | #else
|
| 522 | if (count < sizeof(struct dlm_write_request))
|
| 523 | #endif
|
| 524 | return -EINVAL;
|
| 525 |
|
| 526 | |
| 527 | * can't compare against COMPAT/dlm_write_request32 because
|
| 528 | * we don't yet know if is64bit is zero
|
| 529 |
|
| 530 | if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN)
|
| 531 | return -EINVAL;
|
| 532 |
|
| 533 | kbuf = memdup_user_nul(buf, count);
|
| 534 | if (IS_ERR(kbuf))
|
| 535 | return PTR_ERR(kbuf);
|
| 536 |
|
| 537 | if (check_version(kbuf)) {
|
| 538 | error = -EBADE;
|
| 539 | goto out_free;
|
| 540 | }
|
| 541 |
|
| 542 | #ifdef CONFIG_COMPAT
|
| 543 | if (!kbuf->is64bit) {
|
| 544 | struct dlm_write_request32 *k32buf;
|
| 545 | int namelen = 0;
|
| 546 |
|
| 547 | if (count > sizeof(struct dlm_write_request32))
|
| 548 | namelen = count - sizeof(struct dlm_write_request32);
|
| 549 | name_payload = namelen;
|
| 550 |
|
| 551 | k32buf = (struct dlm_write_request32 *)kbuf;
|
| 552 |
|
| 553 |
|
| 554 | kbuf = kzalloc(sizeof(struct dlm_write_request) + namelen + 1,
|
| 555 | GFP_NOFS);
|
| 556 | if (!kbuf) {
|
| 557 | kfree(k32buf);
|
| 558 | return -ENOMEM;
|
| 559 | }
|
| 560 |
|
| 561 | if (proc)
|
| 562 | set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
|
| 563 |
|
| 564 | compat_input(kbuf, k32buf, namelen);
|
| 565 | kfree(k32buf);
|
| 566 | } else {
|
| 567 | if (count > sizeof(*kbuf))
|
| 568 | name_payload = count - sizeof(*kbuf);
|
| 569 | }
|
| 570 | #else
|
| 571 | if (count > sizeof(*kbuf))
|
| 572 | name_payload = count - sizeof(*kbuf);
|
| 573 | #endif
|
| 574 |
|
| 575 |
|
| 576 | if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) &&
|
| 577 | (proc && test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))) {
|
| 578 | error = -EINVAL;
|
| 579 | goto out_free;
|
| 580 | }
|
| 581 |
|
| 582 | if (kbuf->cmd == DLM_USER_LOCK &&
|
| 583 | !(kbuf->i.lock.flags & DLM_LKF_CONVERT)) {
|
| 584 | if (kbuf->i.lock.namelen > name_payload ||
|
| 585 | kbuf->i.lock.namelen > DLM_RESNAME_MAXLEN) {
|
| 586 | error = -EINVAL;
|
| 587 | goto out_free;
|
| 588 | }
|
| 589 | }
|
| 590 |
|
| 591 | error = -EINVAL;
|
| 592 |
|
| 593 | switch (kbuf->cmd)
|
| 594 | {
|
| 595 | case DLM_USER_LOCK:
|
| 596 | if (!proc) {
|
| 597 | log_print("no locking on control device");
|
| 598 | goto out_free;
|
| 599 | }
|
| 600 | error = device_user_lock(proc, &kbuf->i.lock);
|
| 601 | break;
|
| 602 |
|
| 603 | case DLM_USER_UNLOCK:
|
| 604 | if (!proc) {
|
| 605 | log_print("no locking on control device");
|
| 606 | goto out_free;
|
| 607 | }
|
| 608 | error = device_user_unlock(proc, &kbuf->i.lock);
|
| 609 | break;
|
| 610 |
|
| 611 | case DLM_USER_DEADLOCK:
|
| 612 | if (!proc) {
|
| 613 | log_print("no locking on control device");
|
| 614 | goto out_free;
|
| 615 | }
|
| 616 | error = device_user_deadlock(proc, &kbuf->i.lock);
|
| 617 | break;
|
| 618 |
|
| 619 | case DLM_USER_CREATE_LOCKSPACE:
|
| 620 | if (proc) {
|
| 621 | log_print("create/remove only on control device");
|
| 622 | goto out_free;
|
| 623 | }
|
| 624 | error = device_create_lockspace(&kbuf->i.lspace);
|
| 625 | break;
|
| 626 |
|
| 627 | case DLM_USER_REMOVE_LOCKSPACE:
|
| 628 | if (proc) {
|
| 629 | log_print("create/remove only on control device");
|
| 630 | goto out_free;
|
| 631 | }
|
| 632 | error = device_remove_lockspace(&kbuf->i.lspace);
|
| 633 | break;
|
| 634 |
|
| 635 | case DLM_USER_PURGE:
|
| 636 | if (!proc) {
|
| 637 | log_print("no locking on control device");
|
| 638 | goto out_free;
|
| 639 | }
|
| 640 | error = device_user_purge(proc, &kbuf->i.purge);
|
| 641 | break;
|
| 642 |
|
| 643 | default:
|
| 644 | log_print("Unknown command passed to DLM device : %d\n",
|
| 645 | kbuf->cmd);
|
| 646 | }
|
| 647 |
|
| 648 | out_free:
|
| 649 | kfree(kbuf);
|
| 650 | return error;
|
| 651 | }
|
| 652 |
|
| 653 | |
| 654 | hanging off the open file that's used to keep track of locks owned by the
|
| 655 | process and asts that need to be delivered to the process.
|
| 656 |
|
| 657 | static int device_open(struct inode *inode, struct file *file)
|
| 658 | {
|
| 659 | struct dlm_user_proc *proc;
|
| 660 | struct dlm_ls *ls;
|
| 661 |
|
| 662 | ls = dlm_find_lockspace_device(iminor(inode));
|
| 663 | if (!ls)
|
| 664 | return -ENOENT;
|
| 665 |
|
| 666 | proc = kzalloc_obj(struct dlm_user_proc, GFP_NOFS);
|
| 667 | if (!proc) {
|
| 668 | dlm_put_lockspace(ls);
|
| 669 | return -ENOMEM;
|
| 670 | }
|
| 671 |
|
| 672 | proc->lockspace = ls;
|
| 673 | INIT_LIST_HEAD(&proc->asts);
|
| 674 | INIT_LIST_HEAD(&proc->locks);
|
| 675 | INIT_LIST_HEAD(&proc->unlocking);
|
| 676 | spin_lock_init(&proc->asts_spin);
|
| 677 | spin_lock_init(&proc->locks_spin);
|
| 678 | init_waitqueue_head(&proc->wait);
|
| 679 | file->private_data = proc;
|
| 680 |
|
| 681 | return 0;
|
| 682 | }
|
| 683 |
|
| 684 | static int device_close(struct inode *inode, struct file *file)
|
| 685 | {
|
| 686 | struct dlm_user_proc *proc = file->private_data;
|
| 687 | struct dlm_ls *ls;
|
| 688 |
|
| 689 | ls = dlm_find_lockspace_local(proc->lockspace);
|
| 690 | if (!ls)
|
| 691 | return -ENOENT;
|
| 692 |
|
| 693 | set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags);
|
| 694 |
|
| 695 | dlm_clear_proc_locks(ls, proc);
|
| 696 |
|
| 697 | |
| 698 | so there's no chance of dlm_user_add_ast() being called and
|
| 699 | looking for lkb->ua->proc
|
| 700 |
|
| 701 | kfree(proc);
|
| 702 | file->private_data = NULL;
|
| 703 |
|
| 704 | dlm_put_lockspace(ls);
|
| 705 | dlm_put_lockspace(ls);
|
| 706 |
|
| 707 | |
| 708 | device_remove_lockspace()
|
| 709 |
|
| 710 | return 0;
|
| 711 | }
|
| 712 |
|
| 713 | static int copy_result_to_user(struct dlm_user_args *ua, int compat,
|
| 714 | uint32_t flags, int mode, int copy_lvb,
|
| 715 | char __user *buf, size_t count)
|
| 716 | {
|
| 717 | #ifdef CONFIG_COMPAT
|
| 718 | struct dlm_lock_result32 result32;
|
| 719 | #endif
|
| 720 | struct dlm_lock_result result;
|
| 721 | void *resultptr;
|
| 722 | int error=0;
|
| 723 | int len;
|
| 724 | int struct_len;
|
| 725 |
|
| 726 | memset(&result, 0, sizeof(struct dlm_lock_result));
|
| 727 | result.version[0] = DLM_DEVICE_VERSION_MAJOR;
|
| 728 | result.version[1] = DLM_DEVICE_VERSION_MINOR;
|
| 729 | result.version[2] = DLM_DEVICE_VERSION_PATCH;
|
| 730 | memcpy(&result.lksb, &ua->lksb, offsetof(struct dlm_lksb, sb_lvbptr));
|
| 731 | result.user_lksb = ua->user_lksb;
|
| 732 |
|
| 733 | |
| 734 | in a conversion unless the conversion is successful. See code
|
| 735 | in dlm_user_convert() for updating ua from ua_tmp. OpenVMS, though,
|
| 736 | notes that a new blocking AST address and parameter are set even if
|
| 737 | the conversion fails, so maybe we should just do that.
|
| 738 |
|
| 739 | if (flags & DLM_CB_BAST) {
|
| 740 | result.user_astaddr = ua->bastaddr;
|
| 741 | result.user_astparam = ua->bastparam;
|
| 742 | result.bast_mode = mode;
|
| 743 | } else {
|
| 744 | result.user_astaddr = ua->castaddr;
|
| 745 | result.user_astparam = ua->castparam;
|
| 746 | }
|
| 747 |
|
| 748 | #ifdef CONFIG_COMPAT
|
| 749 | if (compat)
|
| 750 | len = sizeof(struct dlm_lock_result32);
|
| 751 | else
|
| 752 | #endif
|
| 753 | len = sizeof(struct dlm_lock_result);
|
| 754 | struct_len = len;
|
| 755 |
|
| 756 | |
| 757 | the user buffer has space for it
|
| 758 |
|
| 759 | if (copy_lvb && ua->lksb.sb_lvbptr && count >= len + DLM_USER_LVB_LEN) {
|
| 760 | if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
|
| 761 | DLM_USER_LVB_LEN)) {
|
| 762 | error = -EFAULT;
|
| 763 | goto out;
|
| 764 | }
|
| 765 |
|
| 766 | result.lvb_offset = len;
|
| 767 | len += DLM_USER_LVB_LEN;
|
| 768 | }
|
| 769 |
|
| 770 | result.length = len;
|
| 771 | resultptr = &result;
|
| 772 | #ifdef CONFIG_COMPAT
|
| 773 | if (compat) {
|
| 774 | compat_output(&result, &result32);
|
| 775 | resultptr = &result32;
|
| 776 | }
|
| 777 | #endif
|
| 778 |
|
| 779 | if (copy_to_user(buf, resultptr, struct_len))
|
| 780 | error = -EFAULT;
|
| 781 | else
|
| 782 | error = len;
|
| 783 | out:
|
| 784 | return error;
|
| 785 | }
|
| 786 |
|
| 787 | static int copy_version_to_user(char __user *buf, size_t count)
|
| 788 | {
|
| 789 | struct dlm_device_version ver;
|
| 790 |
|
| 791 | memset(&ver, 0, sizeof(struct dlm_device_version));
|
| 792 | ver.version[0] = DLM_DEVICE_VERSION_MAJOR;
|
| 793 | ver.version[1] = DLM_DEVICE_VERSION_MINOR;
|
| 794 | ver.version[2] = DLM_DEVICE_VERSION_PATCH;
|
| 795 |
|
| 796 | if (copy_to_user(buf, &ver, sizeof(struct dlm_device_version)))
|
| 797 | return -EFAULT;
|
| 798 | return sizeof(struct dlm_device_version);
|
| 799 | }
|
| 800 |
|
| 801 |
|
| 802 |
|
| 803 | static ssize_t device_read(struct file *file, char __user *buf, size_t count,
|
| 804 | loff_t *ppos)
|
| 805 | {
|
| 806 | struct dlm_user_proc *proc = file->private_data;
|
| 807 | DECLARE_WAITQUEUE(wait, current);
|
| 808 | struct dlm_callback *cb;
|
| 809 | int rv, ret;
|
| 810 |
|
| 811 | if (count == sizeof(struct dlm_device_version)) {
|
| 812 | rv = copy_version_to_user(buf, count);
|
| 813 | return rv;
|
| 814 | }
|
| 815 |
|
| 816 | if (!proc) {
|
| 817 | log_print("non-version read from control device %zu", count);
|
| 818 | return -EINVAL;
|
| 819 | }
|
| 820 |
|
| 821 | #ifdef CONFIG_COMPAT
|
| 822 | if (count < sizeof(struct dlm_lock_result32))
|
| 823 | #else
|
| 824 | if (count < sizeof(struct dlm_lock_result))
|
| 825 | #endif
|
| 826 | return -EINVAL;
|
| 827 |
|
| 828 |
|
| 829 | if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
|
| 830 | return -EINVAL;
|
| 831 |
|
| 832 | spin_lock_bh(&proc->asts_spin);
|
| 833 | if (list_empty(&proc->asts)) {
|
| 834 | if (file->f_flags & O_NONBLOCK) {
|
| 835 | spin_unlock_bh(&proc->asts_spin);
|
| 836 | return -EAGAIN;
|
| 837 | }
|
| 838 |
|
| 839 | add_wait_queue(&proc->wait, &wait);
|
| 840 |
|
| 841 | repeat:
|
| 842 | set_current_state(TASK_INTERRUPTIBLE);
|
| 843 | if (list_empty(&proc->asts) && !signal_pending(current)) {
|
| 844 | spin_unlock_bh(&proc->asts_spin);
|
| 845 | schedule();
|
| 846 | spin_lock_bh(&proc->asts_spin);
|
| 847 | goto repeat;
|
| 848 | }
|
| 849 | set_current_state(TASK_RUNNING);
|
| 850 | remove_wait_queue(&proc->wait, &wait);
|
| 851 |
|
| 852 | if (signal_pending(current)) {
|
| 853 | spin_unlock_bh(&proc->asts_spin);
|
| 854 | return -ERESTARTSYS;
|
| 855 | }
|
| 856 | }
|
| 857 |
|
| 858 | |
| 859 | without removing lkb_cb_list; so empty lkb_cb_list is always
|
| 860 | consistent with empty lkb_callbacks
|
| 861 |
|
| 862 | cb = list_first_entry(&proc->asts, struct dlm_callback, list);
|
| 863 | list_del(&cb->list);
|
| 864 | spin_unlock_bh(&proc->asts_spin);
|
| 865 |
|
| 866 | if (cb->flags & DLM_CB_BAST) {
|
| 867 | trace_dlm_bast(cb->ls_id, cb->lkb_id, cb->mode, cb->res_name,
|
| 868 | cb->res_length);
|
| 869 | } else if (cb->flags & DLM_CB_CAST) {
|
| 870 | cb->lkb_lksb->sb_status = cb->sb_status;
|
| 871 | cb->lkb_lksb->sb_flags = cb->sb_flags;
|
| 872 | trace_dlm_ast(cb->ls_id, cb->lkb_id, cb->sb_status,
|
| 873 | cb->sb_flags, cb->res_name, cb->res_length);
|
| 874 | }
|
| 875 |
|
| 876 | ret = copy_result_to_user(&cb->ua,
|
| 877 | test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
|
| 878 | cb->flags, cb->mode, cb->copy_lvb, buf, count);
|
| 879 | dlm_free_cb(cb);
|
| 880 | return ret;
|
| 881 | }
|
| 882 |
|
| 883 | static __poll_t device_poll(struct file *file, poll_table *wait)
|
| 884 | {
|
| 885 | struct dlm_user_proc *proc = file->private_data;
|
| 886 |
|
| 887 | poll_wait(file, &proc->wait, wait);
|
| 888 |
|
| 889 | spin_lock_bh(&proc->asts_spin);
|
| 890 | if (!list_empty(&proc->asts)) {
|
| 891 | spin_unlock_bh(&proc->asts_spin);
|
| 892 | return EPOLLIN | EPOLLRDNORM;
|
| 893 | }
|
| 894 | spin_unlock_bh(&proc->asts_spin);
|
| 895 | return 0;
|
| 896 | }
|
| 897 |
|
| 898 | int dlm_user_daemon_available(void)
|
| 899 | {
|
| 900 | |
| 901 | properly populated configfs)
|
| 902 |
|
| 903 | if (!dlm_our_nodeid())
|
| 904 | return 0;
|
| 905 |
|
| 906 | |
| 907 | know about the monitor device. We assume that if the
|
| 908 | dlm_controld was started (above), but the monitor device
|
| 909 | was never opened, that it's an old version. dlm_controld
|
| 910 | should open the monitor device before populating configfs.
|
| 911 |
|
| 912 | if (dlm_monitor_unused)
|
| 913 | return 1;
|
| 914 |
|
| 915 | return atomic_read(&dlm_monitor_opened) ? 1 : 0;
|
| 916 | }
|
| 917 |
|
| 918 | static int ctl_device_open(struct inode *inode, struct file *file)
|
| 919 | {
|
| 920 | file->private_data = NULL;
|
| 921 | return 0;
|
| 922 | }
|
| 923 |
|
| 924 | static int ctl_device_close(struct inode *inode, struct file *file)
|
| 925 | {
|
| 926 | return 0;
|
| 927 | }
|
| 928 |
|
| 929 | static int monitor_device_open(struct inode *inode, struct file *file)
|
| 930 | {
|
| 931 |
|
| 932 | if (!capable(CAP_SYS_ADMIN))
|
| 933 | return -EPERM;
|
| 934 |
|
| 935 | atomic_inc(&dlm_monitor_opened);
|
| 936 | dlm_monitor_unused = 0;
|
| 937 | return 0;
|
| 938 | }
|
| 939 |
|
| 940 | static int monitor_device_close(struct inode *inode, struct file *file)
|
| 941 | {
|
| 942 | if (atomic_dec_and_test(&dlm_monitor_opened))
|
| 943 | dlm_stop_lockspaces();
|
| 944 | return 0;
|
| 945 | }
|
| 946 |
|
| 947 | static const struct file_operations device_fops = {
|
| 948 | .open = device_open,
|
| 949 | .release = device_close,
|
| 950 | .read = device_read,
|
| 951 | .write = device_write,
|
| 952 | .poll = device_poll,
|
| 953 | .owner = THIS_MODULE,
|
| 954 | .llseek = noop_llseek,
|
| 955 | };
|
| 956 |
|
| 957 | static const struct file_operations ctl_device_fops = {
|
| 958 | .open = ctl_device_open,
|
| 959 | .release = ctl_device_close,
|
| 960 | .read = device_read,
|
| 961 | .write = device_write,
|
| 962 | .owner = THIS_MODULE,
|
| 963 | .llseek = noop_llseek,
|
| 964 | };
|
| 965 |
|
| 966 | static struct miscdevice ctl_device = {
|
| 967 | .name = "dlm-control",
|
| 968 | .fops = &ctl_device_fops,
|
| 969 | .minor = MISC_DYNAMIC_MINOR,
|
| 970 | };
|
| 971 |
|
| 972 | static const struct file_operations monitor_device_fops = {
|
| 973 | .open = monitor_device_open,
|
| 974 | .release = monitor_device_close,
|
| 975 | .owner = THIS_MODULE,
|
| 976 | .llseek = noop_llseek,
|
| 977 | };
|
| 978 |
|
| 979 | static struct miscdevice monitor_device = {
|
| 980 | .name = "dlm-monitor",
|
| 981 | .fops = &monitor_device_fops,
|
| 982 | .minor = MISC_DYNAMIC_MINOR,
|
| 983 | .mode = 0600,
|
| 984 | };
|
| 985 |
|
| 986 | int __init dlm_user_init(void)
|
| 987 | {
|
| 988 | int error;
|
| 989 |
|
| 990 | atomic_set(&dlm_monitor_opened, 0);
|
| 991 |
|
| 992 | error = misc_register(&ctl_device);
|
| 993 | if (error) {
|
| 994 | log_print("misc_register failed for control device");
|
| 995 | goto out;
|
| 996 | }
|
| 997 |
|
| 998 | error = misc_register(&monitor_device);
|
| 999 | if (error) {
|
| 1000 | log_print("misc_register failed for monitor device");
|
| 1001 | misc_deregister(&ctl_device);
|
| 1002 | }
|
| 1003 | out:
|
| 1004 | return error;
|
| 1005 | }
|
| 1006 |
|
| 1007 | void dlm_user_exit(void)
|
| 1008 | {
|
| 1009 | misc_deregister(&ctl_device);
|
| 1010 | misc_deregister(&monitor_device);
|
| 1011 | }
|
| 1012 |
|