1597d0caeSDavid Teigland /* 2ef0c2bb0SDavid Teigland * Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved. 3597d0caeSDavid Teigland * 4597d0caeSDavid Teigland * This copyrighted material is made available to anyone wishing to use, 5597d0caeSDavid Teigland * modify, copy, or redistribute it subject to the terms and conditions 6597d0caeSDavid Teigland * of the GNU General Public License v.2. 7597d0caeSDavid Teigland */ 8597d0caeSDavid Teigland 9597d0caeSDavid Teigland #include <linux/miscdevice.h> 10597d0caeSDavid Teigland #include <linux/init.h> 11597d0caeSDavid Teigland #include <linux/wait.h> 12597d0caeSDavid Teigland #include <linux/module.h> 13597d0caeSDavid Teigland #include <linux/file.h> 14597d0caeSDavid Teigland #include <linux/fs.h> 15597d0caeSDavid Teigland #include <linux/poll.h> 16597d0caeSDavid Teigland #include <linux/signal.h> 17597d0caeSDavid Teigland #include <linux/spinlock.h> 18597d0caeSDavid Teigland #include <linux/dlm.h> 19597d0caeSDavid Teigland #include <linux/dlm_device.h> 20597d0caeSDavid Teigland 21597d0caeSDavid Teigland #include "dlm_internal.h" 22597d0caeSDavid Teigland #include "lockspace.h" 23597d0caeSDavid Teigland #include "lock.h" 24597d0caeSDavid Teigland #include "lvb_table.h" 2584c6e8cdSAdrian Bunk #include "user.h" 26597d0caeSDavid Teigland 27597d0caeSDavid Teigland static const char *name_prefix="dlm"; 28597d0caeSDavid Teigland static struct miscdevice ctl_device; 2900977a59SArjan van de Ven static const struct file_operations device_fops; 30597d0caeSDavid Teigland 31597d0caeSDavid Teigland #ifdef CONFIG_COMPAT 32597d0caeSDavid Teigland 33597d0caeSDavid Teigland struct dlm_lock_params32 { 34597d0caeSDavid Teigland __u8 mode; 35597d0caeSDavid Teigland __u8 namelen; 36597d0caeSDavid Teigland __u16 flags; 37597d0caeSDavid Teigland __u32 lkid; 38597d0caeSDavid Teigland __u32 parent; 39597d0caeSDavid Teigland 40597d0caeSDavid Teigland __u32 castparam; 41597d0caeSDavid Teigland __u32 castaddr; 42597d0caeSDavid Teigland __u32 bastparam; 43597d0caeSDavid Teigland __u32 bastaddr; 44597d0caeSDavid Teigland __u32 lksb; 45597d0caeSDavid Teigland 46597d0caeSDavid Teigland char lvb[DLM_USER_LVB_LEN]; 47597d0caeSDavid Teigland char name[0]; 48597d0caeSDavid Teigland }; 49597d0caeSDavid Teigland 50597d0caeSDavid Teigland struct dlm_write_request32 { 51597d0caeSDavid Teigland __u32 version[3]; 52597d0caeSDavid Teigland __u8 cmd; 53597d0caeSDavid Teigland __u8 is64bit; 54597d0caeSDavid Teigland __u8 unused[2]; 55597d0caeSDavid Teigland 56597d0caeSDavid Teigland union { 57597d0caeSDavid Teigland struct dlm_lock_params32 lock; 58597d0caeSDavid Teigland struct dlm_lspace_params lspace; 59*72c2be77SDavid Teigland struct dlm_purge_params purge; 60597d0caeSDavid Teigland } i; 61597d0caeSDavid Teigland }; 62597d0caeSDavid Teigland 63597d0caeSDavid Teigland struct dlm_lksb32 { 64597d0caeSDavid Teigland __u32 sb_status; 65597d0caeSDavid Teigland __u32 sb_lkid; 66597d0caeSDavid Teigland __u8 sb_flags; 67597d0caeSDavid Teigland __u32 sb_lvbptr; 68597d0caeSDavid Teigland }; 69597d0caeSDavid Teigland 70597d0caeSDavid Teigland struct dlm_lock_result32 { 71597d0caeSDavid Teigland __u32 length; 72597d0caeSDavid Teigland __u32 user_astaddr; 73597d0caeSDavid Teigland __u32 user_astparam; 74597d0caeSDavid Teigland __u32 user_lksb; 75597d0caeSDavid Teigland struct dlm_lksb32 lksb; 76597d0caeSDavid Teigland __u8 bast_mode; 77597d0caeSDavid Teigland __u8 unused[3]; 78597d0caeSDavid Teigland /* Offsets may be zero if no data is present */ 79597d0caeSDavid Teigland __u32 lvb_offset; 80597d0caeSDavid Teigland }; 81597d0caeSDavid Teigland 82597d0caeSDavid Teigland static void compat_input(struct dlm_write_request *kb, 83597d0caeSDavid Teigland struct dlm_write_request32 *kb32) 84597d0caeSDavid Teigland { 85597d0caeSDavid Teigland kb->version[0] = kb32->version[0]; 86597d0caeSDavid Teigland kb->version[1] = kb32->version[1]; 87597d0caeSDavid Teigland kb->version[2] = kb32->version[2]; 88597d0caeSDavid Teigland 89597d0caeSDavid Teigland kb->cmd = kb32->cmd; 90597d0caeSDavid Teigland kb->is64bit = kb32->is64bit; 91597d0caeSDavid Teigland if (kb->cmd == DLM_USER_CREATE_LOCKSPACE || 92597d0caeSDavid Teigland kb->cmd == DLM_USER_REMOVE_LOCKSPACE) { 93597d0caeSDavid Teigland kb->i.lspace.flags = kb32->i.lspace.flags; 94597d0caeSDavid Teigland kb->i.lspace.minor = kb32->i.lspace.minor; 95597d0caeSDavid Teigland strcpy(kb->i.lspace.name, kb32->i.lspace.name); 96*72c2be77SDavid Teigland } else if (kb->cmd == DLM_USER_PURGE) { 97*72c2be77SDavid Teigland kb->i.purge.nodeid = kb32->i.purge.nodeid; 98*72c2be77SDavid Teigland kb->i.purge.pid = kb32->i.purge.pid; 99597d0caeSDavid Teigland } else { 100597d0caeSDavid Teigland kb->i.lock.mode = kb32->i.lock.mode; 101597d0caeSDavid Teigland kb->i.lock.namelen = kb32->i.lock.namelen; 102597d0caeSDavid Teigland kb->i.lock.flags = kb32->i.lock.flags; 103597d0caeSDavid Teigland kb->i.lock.lkid = kb32->i.lock.lkid; 104597d0caeSDavid Teigland kb->i.lock.parent = kb32->i.lock.parent; 105597d0caeSDavid Teigland kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam; 106597d0caeSDavid Teigland kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr; 107597d0caeSDavid Teigland kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam; 108597d0caeSDavid Teigland kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr; 109597d0caeSDavid Teigland kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb; 110597d0caeSDavid Teigland memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN); 111597d0caeSDavid Teigland memcpy(kb->i.lock.name, kb32->i.lock.name, kb->i.lock.namelen); 112597d0caeSDavid Teigland } 113597d0caeSDavid Teigland } 114597d0caeSDavid Teigland 115597d0caeSDavid Teigland static void compat_output(struct dlm_lock_result *res, 116597d0caeSDavid Teigland struct dlm_lock_result32 *res32) 117597d0caeSDavid Teigland { 118597d0caeSDavid Teigland res32->length = res->length - (sizeof(struct dlm_lock_result) - 119597d0caeSDavid Teigland sizeof(struct dlm_lock_result32)); 120597d0caeSDavid Teigland res32->user_astaddr = (__u32)(long)res->user_astaddr; 121597d0caeSDavid Teigland res32->user_astparam = (__u32)(long)res->user_astparam; 122597d0caeSDavid Teigland res32->user_lksb = (__u32)(long)res->user_lksb; 123597d0caeSDavid Teigland res32->bast_mode = res->bast_mode; 124597d0caeSDavid Teigland 125597d0caeSDavid Teigland res32->lvb_offset = res->lvb_offset; 126597d0caeSDavid Teigland res32->length = res->length; 127597d0caeSDavid Teigland 128597d0caeSDavid Teigland res32->lksb.sb_status = res->lksb.sb_status; 129597d0caeSDavid Teigland res32->lksb.sb_flags = res->lksb.sb_flags; 130597d0caeSDavid Teigland res32->lksb.sb_lkid = res->lksb.sb_lkid; 131597d0caeSDavid Teigland res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr; 132597d0caeSDavid Teigland } 133597d0caeSDavid Teigland #endif 134597d0caeSDavid Teigland 135ef0c2bb0SDavid Teigland /* we could possibly check if the cancel of an orphan has resulted in the lkb 136ef0c2bb0SDavid Teigland being removed and then remove that lkb from the orphans list and free it */ 137597d0caeSDavid Teigland 138597d0caeSDavid Teigland void dlm_user_add_ast(struct dlm_lkb *lkb, int type) 139597d0caeSDavid Teigland { 140597d0caeSDavid Teigland struct dlm_ls *ls; 141597d0caeSDavid Teigland struct dlm_user_args *ua; 142597d0caeSDavid Teigland struct dlm_user_proc *proc; 143ef0c2bb0SDavid Teigland int eol = 0, ast_type; 144597d0caeSDavid Teigland 145ef0c2bb0SDavid Teigland if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) 146597d0caeSDavid Teigland return; 147597d0caeSDavid Teigland 148597d0caeSDavid Teigland ls = lkb->lkb_resource->res_ls; 149597d0caeSDavid Teigland mutex_lock(&ls->ls_clear_proc_locks); 150597d0caeSDavid Teigland 151597d0caeSDavid Teigland /* If ORPHAN/DEAD flag is set, it means the process is dead so an ast 152597d0caeSDavid Teigland can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed 153ef0c2bb0SDavid Teigland lkb->ua so we can't try to use it. This second check is necessary 154ef0c2bb0SDavid Teigland for cases where a completion ast is received for an operation that 155ef0c2bb0SDavid Teigland began before clear_proc_locks did its cancel/unlock. */ 156597d0caeSDavid Teigland 157ef0c2bb0SDavid Teigland if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) 158597d0caeSDavid Teigland goto out; 159597d0caeSDavid Teigland 160597d0caeSDavid Teigland DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb);); 161597d0caeSDavid Teigland ua = (struct dlm_user_args *)lkb->lkb_astparam; 162597d0caeSDavid Teigland proc = ua->proc; 163597d0caeSDavid Teigland 164597d0caeSDavid Teigland if (type == AST_BAST && ua->bastaddr == NULL) 165597d0caeSDavid Teigland goto out; 166597d0caeSDavid Teigland 167597d0caeSDavid Teigland spin_lock(&proc->asts_spin); 168ef0c2bb0SDavid Teigland 169ef0c2bb0SDavid Teigland ast_type = lkb->lkb_ast_type; 170ef0c2bb0SDavid Teigland lkb->lkb_ast_type |= type; 171ef0c2bb0SDavid Teigland 172ef0c2bb0SDavid Teigland if (!ast_type) { 173597d0caeSDavid Teigland kref_get(&lkb->lkb_ref); 174597d0caeSDavid Teigland list_add_tail(&lkb->lkb_astqueue, &proc->asts); 175597d0caeSDavid Teigland wake_up_interruptible(&proc->wait); 176597d0caeSDavid Teigland } 177ef0c2bb0SDavid Teigland if (type == AST_COMP && (ast_type & AST_COMP)) 178ef0c2bb0SDavid Teigland log_debug(ls, "ast overlap %x status %x %x", 179ef0c2bb0SDavid Teigland lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags); 180597d0caeSDavid Teigland 181ef0c2bb0SDavid Teigland /* Figure out if this lock is at the end of its life and no longer 182ef0c2bb0SDavid Teigland available for the application to use. The lkb still exists until 183ef0c2bb0SDavid Teigland the final ast is read. A lock becomes EOL in three situations: 184ef0c2bb0SDavid Teigland 1. a noqueue request fails with EAGAIN 185ef0c2bb0SDavid Teigland 2. an unlock completes with EUNLOCK 186ef0c2bb0SDavid Teigland 3. a cancel of a waiting request completes with ECANCEL 187ef0c2bb0SDavid Teigland An EOL lock needs to be removed from the process's list of locks. 188ef0c2bb0SDavid Teigland And we can't allow any new operation on an EOL lock. This is 189ef0c2bb0SDavid Teigland not related to the lifetime of the lkb struct which is managed 190ef0c2bb0SDavid Teigland entirely by refcount. */ 19134e22bedSDavid Teigland 192ef0c2bb0SDavid Teigland if (type == AST_COMP && 193ef0c2bb0SDavid Teigland lkb->lkb_grmode == DLM_LOCK_IV && 194ef0c2bb0SDavid Teigland ua->lksb.sb_status == -EAGAIN) 195ef0c2bb0SDavid Teigland eol = 1; 196ef0c2bb0SDavid Teigland else if (ua->lksb.sb_status == -DLM_EUNLOCK || 197a1bc86e6SDavid Teigland (ua->lksb.sb_status == -DLM_ECANCEL && 198a1bc86e6SDavid Teigland lkb->lkb_grmode == DLM_LOCK_IV)) 199ef0c2bb0SDavid Teigland eol = 1; 200ef0c2bb0SDavid Teigland if (eol) { 201ef0c2bb0SDavid Teigland lkb->lkb_ast_type &= ~AST_BAST; 202ef0c2bb0SDavid Teigland lkb->lkb_flags |= DLM_IFL_ENDOFLIFE; 203ef0c2bb0SDavid Teigland } 204a1bc86e6SDavid Teigland 205597d0caeSDavid Teigland /* We want to copy the lvb to userspace when the completion 206597d0caeSDavid Teigland ast is read if the status is 0, the lock has an lvb and 207597d0caeSDavid Teigland lvb_ops says we should. We could probably have set_lvb_lock() 208597d0caeSDavid Teigland set update_user_lvb instead and not need old_mode */ 209597d0caeSDavid Teigland 210597d0caeSDavid Teigland if ((lkb->lkb_ast_type & AST_COMP) && 211597d0caeSDavid Teigland (lkb->lkb_lksb->sb_status == 0) && 212597d0caeSDavid Teigland lkb->lkb_lksb->sb_lvbptr && 213597d0caeSDavid Teigland dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1]) 214597d0caeSDavid Teigland ua->update_user_lvb = 1; 215597d0caeSDavid Teigland else 216597d0caeSDavid Teigland ua->update_user_lvb = 0; 217597d0caeSDavid Teigland 218597d0caeSDavid Teigland spin_unlock(&proc->asts_spin); 21934e22bedSDavid Teigland 220ef0c2bb0SDavid Teigland if (eol) { 22134e22bedSDavid Teigland spin_lock(&ua->proc->locks_spin); 222ef0c2bb0SDavid Teigland if (!list_empty(&lkb->lkb_ownqueue)) { 22334e22bedSDavid Teigland list_del_init(&lkb->lkb_ownqueue); 22434e22bedSDavid Teigland dlm_put_lkb(lkb); 22534e22bedSDavid Teigland } 226ef0c2bb0SDavid Teigland spin_unlock(&ua->proc->locks_spin); 227ef0c2bb0SDavid Teigland } 228597d0caeSDavid Teigland out: 229597d0caeSDavid Teigland mutex_unlock(&ls->ls_clear_proc_locks); 230597d0caeSDavid Teigland } 231597d0caeSDavid Teigland 232597d0caeSDavid Teigland static int device_user_lock(struct dlm_user_proc *proc, 233597d0caeSDavid Teigland struct dlm_lock_params *params) 234597d0caeSDavid Teigland { 235597d0caeSDavid Teigland struct dlm_ls *ls; 236597d0caeSDavid Teigland struct dlm_user_args *ua; 237597d0caeSDavid Teigland int error = -ENOMEM; 238597d0caeSDavid Teigland 239597d0caeSDavid Teigland ls = dlm_find_lockspace_local(proc->lockspace); 240597d0caeSDavid Teigland if (!ls) 241597d0caeSDavid Teigland return -ENOENT; 242597d0caeSDavid Teigland 243597d0caeSDavid Teigland if (!params->castaddr || !params->lksb) { 244597d0caeSDavid Teigland error = -EINVAL; 245597d0caeSDavid Teigland goto out; 246597d0caeSDavid Teigland } 247597d0caeSDavid Teigland 248597d0caeSDavid Teigland ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL); 249597d0caeSDavid Teigland if (!ua) 250597d0caeSDavid Teigland goto out; 251597d0caeSDavid Teigland ua->proc = proc; 252597d0caeSDavid Teigland ua->user_lksb = params->lksb; 253597d0caeSDavid Teigland ua->castparam = params->castparam; 254597d0caeSDavid Teigland ua->castaddr = params->castaddr; 255597d0caeSDavid Teigland ua->bastparam = params->bastparam; 256597d0caeSDavid Teigland ua->bastaddr = params->bastaddr; 257597d0caeSDavid Teigland 258597d0caeSDavid Teigland if (params->flags & DLM_LKF_CONVERT) 259597d0caeSDavid Teigland error = dlm_user_convert(ls, ua, 260597d0caeSDavid Teigland params->mode, params->flags, 261597d0caeSDavid Teigland params->lkid, params->lvb); 262597d0caeSDavid Teigland else { 263597d0caeSDavid Teigland error = dlm_user_request(ls, ua, 264597d0caeSDavid Teigland params->mode, params->flags, 265597d0caeSDavid Teigland params->name, params->namelen, 266597d0caeSDavid Teigland params->parent); 267597d0caeSDavid Teigland if (!error) 268597d0caeSDavid Teigland error = ua->lksb.sb_lkid; 269597d0caeSDavid Teigland } 270597d0caeSDavid Teigland out: 271597d0caeSDavid Teigland dlm_put_lockspace(ls); 272597d0caeSDavid Teigland return error; 273597d0caeSDavid Teigland } 274597d0caeSDavid Teigland 275597d0caeSDavid Teigland static int device_user_unlock(struct dlm_user_proc *proc, 276597d0caeSDavid Teigland struct dlm_lock_params *params) 277597d0caeSDavid Teigland { 278597d0caeSDavid Teigland struct dlm_ls *ls; 279597d0caeSDavid Teigland struct dlm_user_args *ua; 280597d0caeSDavid Teigland int error = -ENOMEM; 281597d0caeSDavid Teigland 282597d0caeSDavid Teigland ls = dlm_find_lockspace_local(proc->lockspace); 283597d0caeSDavid Teigland if (!ls) 284597d0caeSDavid Teigland return -ENOENT; 285597d0caeSDavid Teigland 286597d0caeSDavid Teigland ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL); 287597d0caeSDavid Teigland if (!ua) 288597d0caeSDavid Teigland goto out; 289597d0caeSDavid Teigland ua->proc = proc; 290597d0caeSDavid Teigland ua->user_lksb = params->lksb; 291597d0caeSDavid Teigland ua->castparam = params->castparam; 292597d0caeSDavid Teigland ua->castaddr = params->castaddr; 293597d0caeSDavid Teigland 294597d0caeSDavid Teigland if (params->flags & DLM_LKF_CANCEL) 295597d0caeSDavid Teigland error = dlm_user_cancel(ls, ua, params->flags, params->lkid); 296597d0caeSDavid Teigland else 297597d0caeSDavid Teigland error = dlm_user_unlock(ls, ua, params->flags, params->lkid, 298597d0caeSDavid Teigland params->lvb); 299597d0caeSDavid Teigland out: 300597d0caeSDavid Teigland dlm_put_lockspace(ls); 301597d0caeSDavid Teigland return error; 302597d0caeSDavid Teigland } 303597d0caeSDavid Teigland 304254da030SPatrick Caulfield static int create_misc_device(struct dlm_ls *ls, char *name) 305254da030SPatrick Caulfield { 306254da030SPatrick Caulfield int error, len; 307254da030SPatrick Caulfield 308254da030SPatrick Caulfield error = -ENOMEM; 309254da030SPatrick Caulfield len = strlen(name) + strlen(name_prefix) + 2; 310254da030SPatrick Caulfield ls->ls_device.name = kzalloc(len, GFP_KERNEL); 311254da030SPatrick Caulfield if (!ls->ls_device.name) 312254da030SPatrick Caulfield goto fail; 313254da030SPatrick Caulfield 314254da030SPatrick Caulfield snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix, 315254da030SPatrick Caulfield name); 316254da030SPatrick Caulfield ls->ls_device.fops = &device_fops; 317254da030SPatrick Caulfield ls->ls_device.minor = MISC_DYNAMIC_MINOR; 318254da030SPatrick Caulfield 319254da030SPatrick Caulfield error = misc_register(&ls->ls_device); 320254da030SPatrick Caulfield if (error) { 321254da030SPatrick Caulfield kfree(ls->ls_device.name); 322254da030SPatrick Caulfield } 323254da030SPatrick Caulfield fail: 324254da030SPatrick Caulfield return error; 325254da030SPatrick Caulfield } 326254da030SPatrick Caulfield 327*72c2be77SDavid Teigland static int device_user_purge(struct dlm_user_proc *proc, 328*72c2be77SDavid Teigland struct dlm_purge_params *params) 329*72c2be77SDavid Teigland { 330*72c2be77SDavid Teigland struct dlm_ls *ls; 331*72c2be77SDavid Teigland int error; 332*72c2be77SDavid Teigland 333*72c2be77SDavid Teigland ls = dlm_find_lockspace_local(proc->lockspace); 334*72c2be77SDavid Teigland if (!ls) 335*72c2be77SDavid Teigland return -ENOENT; 336*72c2be77SDavid Teigland 337*72c2be77SDavid Teigland error = dlm_user_purge(ls, proc, params->nodeid, params->pid); 338*72c2be77SDavid Teigland 339*72c2be77SDavid Teigland dlm_put_lockspace(ls); 340*72c2be77SDavid Teigland return error; 341*72c2be77SDavid Teigland } 342*72c2be77SDavid Teigland 343597d0caeSDavid Teigland static int device_create_lockspace(struct dlm_lspace_params *params) 344597d0caeSDavid Teigland { 345597d0caeSDavid Teigland dlm_lockspace_t *lockspace; 346597d0caeSDavid Teigland struct dlm_ls *ls; 347254da030SPatrick Caulfield int error; 348597d0caeSDavid Teigland 349597d0caeSDavid Teigland if (!capable(CAP_SYS_ADMIN)) 350597d0caeSDavid Teigland return -EPERM; 351597d0caeSDavid Teigland 352597d0caeSDavid Teigland error = dlm_new_lockspace(params->name, strlen(params->name), 353597d0caeSDavid Teigland &lockspace, 0, DLM_USER_LVB_LEN); 354597d0caeSDavid Teigland if (error) 355597d0caeSDavid Teigland return error; 356597d0caeSDavid Teigland 357597d0caeSDavid Teigland ls = dlm_find_lockspace_local(lockspace); 358597d0caeSDavid Teigland if (!ls) 359597d0caeSDavid Teigland return -ENOENT; 360597d0caeSDavid Teigland 361254da030SPatrick Caulfield error = create_misc_device(ls, params->name); 362597d0caeSDavid Teigland dlm_put_lockspace(ls); 363597d0caeSDavid Teigland 364254da030SPatrick Caulfield if (error) 365597d0caeSDavid Teigland dlm_release_lockspace(lockspace, 0); 366254da030SPatrick Caulfield else 367254da030SPatrick Caulfield error = ls->ls_device.minor; 368254da030SPatrick Caulfield 369597d0caeSDavid Teigland return error; 370597d0caeSDavid Teigland } 371597d0caeSDavid Teigland 372597d0caeSDavid Teigland static int device_remove_lockspace(struct dlm_lspace_params *params) 373597d0caeSDavid Teigland { 374597d0caeSDavid Teigland dlm_lockspace_t *lockspace; 375597d0caeSDavid Teigland struct dlm_ls *ls; 376c6e6f0baSDavid Teigland int error, force = 0; 377597d0caeSDavid Teigland 378597d0caeSDavid Teigland if (!capable(CAP_SYS_ADMIN)) 379597d0caeSDavid Teigland return -EPERM; 380597d0caeSDavid Teigland 381597d0caeSDavid Teigland ls = dlm_find_lockspace_device(params->minor); 382597d0caeSDavid Teigland if (!ls) 383597d0caeSDavid Teigland return -ENOENT; 384597d0caeSDavid Teigland 385254da030SPatrick Caulfield /* Deregister the misc device first, so we don't have 386254da030SPatrick Caulfield * a device that's not attached to a lockspace. If 387254da030SPatrick Caulfield * dlm_release_lockspace fails then we can recreate it 388254da030SPatrick Caulfield */ 389597d0caeSDavid Teigland error = misc_deregister(&ls->ls_device); 390597d0caeSDavid Teigland if (error) { 391597d0caeSDavid Teigland dlm_put_lockspace(ls); 392597d0caeSDavid Teigland goto out; 393597d0caeSDavid Teigland } 394597d0caeSDavid Teigland kfree(ls->ls_device.name); 395597d0caeSDavid Teigland 396c6e6f0baSDavid Teigland if (params->flags & DLM_USER_LSFLG_FORCEFREE) 397c6e6f0baSDavid Teigland force = 2; 398c6e6f0baSDavid Teigland 399597d0caeSDavid Teigland lockspace = ls->ls_local_handle; 400597d0caeSDavid Teigland 401597d0caeSDavid Teigland /* dlm_release_lockspace waits for references to go to zero, 402597d0caeSDavid Teigland so all processes will need to close their device for the ls 403597d0caeSDavid Teigland before the release will procede */ 404597d0caeSDavid Teigland 405597d0caeSDavid Teigland dlm_put_lockspace(ls); 406c6e6f0baSDavid Teigland error = dlm_release_lockspace(lockspace, force); 407254da030SPatrick Caulfield if (error) 408254da030SPatrick Caulfield create_misc_device(ls, ls->ls_name); 409597d0caeSDavid Teigland out: 410597d0caeSDavid Teigland return error; 411597d0caeSDavid Teigland } 412597d0caeSDavid Teigland 413597d0caeSDavid Teigland /* Check the user's version matches ours */ 414597d0caeSDavid Teigland static int check_version(struct dlm_write_request *req) 415597d0caeSDavid Teigland { 416597d0caeSDavid Teigland if (req->version[0] != DLM_DEVICE_VERSION_MAJOR || 417597d0caeSDavid Teigland (req->version[0] == DLM_DEVICE_VERSION_MAJOR && 418597d0caeSDavid Teigland req->version[1] > DLM_DEVICE_VERSION_MINOR)) { 419597d0caeSDavid Teigland 420597d0caeSDavid Teigland printk(KERN_DEBUG "dlm: process %s (%d) version mismatch " 421597d0caeSDavid Teigland "user (%d.%d.%d) kernel (%d.%d.%d)\n", 422597d0caeSDavid Teigland current->comm, 423597d0caeSDavid Teigland current->pid, 424597d0caeSDavid Teigland req->version[0], 425597d0caeSDavid Teigland req->version[1], 426597d0caeSDavid Teigland req->version[2], 427597d0caeSDavid Teigland DLM_DEVICE_VERSION_MAJOR, 428597d0caeSDavid Teigland DLM_DEVICE_VERSION_MINOR, 429597d0caeSDavid Teigland DLM_DEVICE_VERSION_PATCH); 430597d0caeSDavid Teigland return -EINVAL; 431597d0caeSDavid Teigland } 432597d0caeSDavid Teigland return 0; 433597d0caeSDavid Teigland } 434597d0caeSDavid Teigland 435597d0caeSDavid Teigland /* 436597d0caeSDavid Teigland * device_write 437597d0caeSDavid Teigland * 438597d0caeSDavid Teigland * device_user_lock 439597d0caeSDavid Teigland * dlm_user_request -> request_lock 440597d0caeSDavid Teigland * dlm_user_convert -> convert_lock 441597d0caeSDavid Teigland * 442597d0caeSDavid Teigland * device_user_unlock 443597d0caeSDavid Teigland * dlm_user_unlock -> unlock_lock 444597d0caeSDavid Teigland * dlm_user_cancel -> cancel_lock 445597d0caeSDavid Teigland * 446597d0caeSDavid Teigland * device_create_lockspace 447597d0caeSDavid Teigland * dlm_new_lockspace 448597d0caeSDavid Teigland * 449597d0caeSDavid Teigland * device_remove_lockspace 450597d0caeSDavid Teigland * dlm_release_lockspace 451597d0caeSDavid Teigland */ 452597d0caeSDavid Teigland 453597d0caeSDavid Teigland /* a write to a lockspace device is a lock or unlock request, a write 454597d0caeSDavid Teigland to the control device is to create/remove a lockspace */ 455597d0caeSDavid Teigland 456597d0caeSDavid Teigland static ssize_t device_write(struct file *file, const char __user *buf, 457597d0caeSDavid Teigland size_t count, loff_t *ppos) 458597d0caeSDavid Teigland { 459597d0caeSDavid Teigland struct dlm_user_proc *proc = file->private_data; 460597d0caeSDavid Teigland struct dlm_write_request *kbuf; 461597d0caeSDavid Teigland sigset_t tmpsig, allsigs; 462597d0caeSDavid Teigland int error; 463597d0caeSDavid Teigland 464597d0caeSDavid Teigland #ifdef CONFIG_COMPAT 465597d0caeSDavid Teigland if (count < sizeof(struct dlm_write_request32)) 466597d0caeSDavid Teigland #else 467597d0caeSDavid Teigland if (count < sizeof(struct dlm_write_request)) 468597d0caeSDavid Teigland #endif 469597d0caeSDavid Teigland return -EINVAL; 470597d0caeSDavid Teigland 471597d0caeSDavid Teigland kbuf = kmalloc(count, GFP_KERNEL); 472597d0caeSDavid Teigland if (!kbuf) 473597d0caeSDavid Teigland return -ENOMEM; 474597d0caeSDavid Teigland 475597d0caeSDavid Teigland if (copy_from_user(kbuf, buf, count)) { 476597d0caeSDavid Teigland error = -EFAULT; 477597d0caeSDavid Teigland goto out_free; 478597d0caeSDavid Teigland } 479597d0caeSDavid Teigland 480597d0caeSDavid Teigland if (check_version(kbuf)) { 481597d0caeSDavid Teigland error = -EBADE; 482597d0caeSDavid Teigland goto out_free; 483597d0caeSDavid Teigland } 484597d0caeSDavid Teigland 485597d0caeSDavid Teigland #ifdef CONFIG_COMPAT 486597d0caeSDavid Teigland if (!kbuf->is64bit) { 487597d0caeSDavid Teigland struct dlm_write_request32 *k32buf; 488597d0caeSDavid Teigland k32buf = (struct dlm_write_request32 *)kbuf; 489597d0caeSDavid Teigland kbuf = kmalloc(count + (sizeof(struct dlm_write_request) - 490597d0caeSDavid Teigland sizeof(struct dlm_write_request32)), GFP_KERNEL); 491597d0caeSDavid Teigland if (!kbuf) 492597d0caeSDavid Teigland return -ENOMEM; 493597d0caeSDavid Teigland 494597d0caeSDavid Teigland if (proc) 495597d0caeSDavid Teigland set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); 496597d0caeSDavid Teigland compat_input(kbuf, k32buf); 497597d0caeSDavid Teigland kfree(k32buf); 498597d0caeSDavid Teigland } 499597d0caeSDavid Teigland #endif 500597d0caeSDavid Teigland 501597d0caeSDavid Teigland /* do we really need this? can a write happen after a close? */ 502597d0caeSDavid Teigland if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) && 503597d0caeSDavid Teigland test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags)) 504597d0caeSDavid Teigland return -EINVAL; 505597d0caeSDavid Teigland 506597d0caeSDavid Teigland sigfillset(&allsigs); 507597d0caeSDavid Teigland sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); 508597d0caeSDavid Teigland 509597d0caeSDavid Teigland error = -EINVAL; 510597d0caeSDavid Teigland 511597d0caeSDavid Teigland switch (kbuf->cmd) 512597d0caeSDavid Teigland { 513597d0caeSDavid Teigland case DLM_USER_LOCK: 514597d0caeSDavid Teigland if (!proc) { 515597d0caeSDavid Teigland log_print("no locking on control device"); 516597d0caeSDavid Teigland goto out_sig; 517597d0caeSDavid Teigland } 518597d0caeSDavid Teigland error = device_user_lock(proc, &kbuf->i.lock); 519597d0caeSDavid Teigland break; 520597d0caeSDavid Teigland 521597d0caeSDavid Teigland case DLM_USER_UNLOCK: 522597d0caeSDavid Teigland if (!proc) { 523597d0caeSDavid Teigland log_print("no locking on control device"); 524597d0caeSDavid Teigland goto out_sig; 525597d0caeSDavid Teigland } 526597d0caeSDavid Teigland error = device_user_unlock(proc, &kbuf->i.lock); 527597d0caeSDavid Teigland break; 528597d0caeSDavid Teigland 529597d0caeSDavid Teigland case DLM_USER_CREATE_LOCKSPACE: 530597d0caeSDavid Teigland if (proc) { 531597d0caeSDavid Teigland log_print("create/remove only on control device"); 532597d0caeSDavid Teigland goto out_sig; 533597d0caeSDavid Teigland } 534597d0caeSDavid Teigland error = device_create_lockspace(&kbuf->i.lspace); 535597d0caeSDavid Teigland break; 536597d0caeSDavid Teigland 537597d0caeSDavid Teigland case DLM_USER_REMOVE_LOCKSPACE: 538597d0caeSDavid Teigland if (proc) { 539597d0caeSDavid Teigland log_print("create/remove only on control device"); 540597d0caeSDavid Teigland goto out_sig; 541597d0caeSDavid Teigland } 542597d0caeSDavid Teigland error = device_remove_lockspace(&kbuf->i.lspace); 543597d0caeSDavid Teigland break; 544597d0caeSDavid Teigland 545*72c2be77SDavid Teigland case DLM_USER_PURGE: 546*72c2be77SDavid Teigland if (!proc) { 547*72c2be77SDavid Teigland log_print("no locking on control device"); 548*72c2be77SDavid Teigland goto out_sig; 549*72c2be77SDavid Teigland } 550*72c2be77SDavid Teigland error = device_user_purge(proc, &kbuf->i.purge); 551*72c2be77SDavid Teigland break; 552*72c2be77SDavid Teigland 553597d0caeSDavid Teigland default: 554597d0caeSDavid Teigland log_print("Unknown command passed to DLM device : %d\n", 555597d0caeSDavid Teigland kbuf->cmd); 556597d0caeSDavid Teigland } 557597d0caeSDavid Teigland 558597d0caeSDavid Teigland out_sig: 559597d0caeSDavid Teigland sigprocmask(SIG_SETMASK, &tmpsig, NULL); 560597d0caeSDavid Teigland recalc_sigpending(); 561597d0caeSDavid Teigland out_free: 562597d0caeSDavid Teigland kfree(kbuf); 563597d0caeSDavid Teigland return error; 564597d0caeSDavid Teigland } 565597d0caeSDavid Teigland 566597d0caeSDavid Teigland /* Every process that opens the lockspace device has its own "proc" structure 567597d0caeSDavid Teigland hanging off the open file that's used to keep track of locks owned by the 568597d0caeSDavid Teigland process and asts that need to be delivered to the process. */ 569597d0caeSDavid Teigland 570597d0caeSDavid Teigland static int device_open(struct inode *inode, struct file *file) 571597d0caeSDavid Teigland { 572597d0caeSDavid Teigland struct dlm_user_proc *proc; 573597d0caeSDavid Teigland struct dlm_ls *ls; 574597d0caeSDavid Teigland 575597d0caeSDavid Teigland ls = dlm_find_lockspace_device(iminor(inode)); 576597d0caeSDavid Teigland if (!ls) 577597d0caeSDavid Teigland return -ENOENT; 578597d0caeSDavid Teigland 579597d0caeSDavid Teigland proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL); 580597d0caeSDavid Teigland if (!proc) { 581597d0caeSDavid Teigland dlm_put_lockspace(ls); 582597d0caeSDavid Teigland return -ENOMEM; 583597d0caeSDavid Teigland } 584597d0caeSDavid Teigland 585597d0caeSDavid Teigland proc->lockspace = ls->ls_local_handle; 586597d0caeSDavid Teigland INIT_LIST_HEAD(&proc->asts); 587597d0caeSDavid Teigland INIT_LIST_HEAD(&proc->locks); 588a1bc86e6SDavid Teigland INIT_LIST_HEAD(&proc->unlocking); 589597d0caeSDavid Teigland spin_lock_init(&proc->asts_spin); 590597d0caeSDavid Teigland spin_lock_init(&proc->locks_spin); 591597d0caeSDavid Teigland init_waitqueue_head(&proc->wait); 592597d0caeSDavid Teigland file->private_data = proc; 593597d0caeSDavid Teigland 594597d0caeSDavid Teigland return 0; 595597d0caeSDavid Teigland } 596597d0caeSDavid Teigland 597597d0caeSDavid Teigland static int device_close(struct inode *inode, struct file *file) 598597d0caeSDavid Teigland { 599597d0caeSDavid Teigland struct dlm_user_proc *proc = file->private_data; 600597d0caeSDavid Teigland struct dlm_ls *ls; 601597d0caeSDavid Teigland sigset_t tmpsig, allsigs; 602597d0caeSDavid Teigland 603597d0caeSDavid Teigland ls = dlm_find_lockspace_local(proc->lockspace); 604597d0caeSDavid Teigland if (!ls) 605597d0caeSDavid Teigland return -ENOENT; 606597d0caeSDavid Teigland 607597d0caeSDavid Teigland sigfillset(&allsigs); 608597d0caeSDavid Teigland sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); 609597d0caeSDavid Teigland 610597d0caeSDavid Teigland set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags); 611597d0caeSDavid Teigland 612597d0caeSDavid Teigland dlm_clear_proc_locks(ls, proc); 613597d0caeSDavid Teigland 614597d0caeSDavid Teigland /* at this point no more lkb's should exist for this lockspace, 615597d0caeSDavid Teigland so there's no chance of dlm_user_add_ast() being called and 616597d0caeSDavid Teigland looking for lkb->ua->proc */ 617597d0caeSDavid Teigland 618597d0caeSDavid Teigland kfree(proc); 619597d0caeSDavid Teigland file->private_data = NULL; 620597d0caeSDavid Teigland 621597d0caeSDavid Teigland dlm_put_lockspace(ls); 622597d0caeSDavid Teigland dlm_put_lockspace(ls); /* for the find in device_open() */ 623597d0caeSDavid Teigland 624597d0caeSDavid Teigland /* FIXME: AUTOFREE: if this ls is no longer used do 625597d0caeSDavid Teigland device_remove_lockspace() */ 626597d0caeSDavid Teigland 627597d0caeSDavid Teigland sigprocmask(SIG_SETMASK, &tmpsig, NULL); 628597d0caeSDavid Teigland recalc_sigpending(); 629597d0caeSDavid Teigland 630597d0caeSDavid Teigland return 0; 631597d0caeSDavid Teigland } 632597d0caeSDavid Teigland 633597d0caeSDavid Teigland static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type, 634597d0caeSDavid Teigland int bmode, char __user *buf, size_t count) 635597d0caeSDavid Teigland { 636597d0caeSDavid Teigland #ifdef CONFIG_COMPAT 637597d0caeSDavid Teigland struct dlm_lock_result32 result32; 638597d0caeSDavid Teigland #endif 639597d0caeSDavid Teigland struct dlm_lock_result result; 640597d0caeSDavid Teigland void *resultptr; 641597d0caeSDavid Teigland int error=0; 642597d0caeSDavid Teigland int len; 643597d0caeSDavid Teigland int struct_len; 644597d0caeSDavid Teigland 645597d0caeSDavid Teigland memset(&result, 0, sizeof(struct dlm_lock_result)); 646597d0caeSDavid Teigland memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb)); 647597d0caeSDavid Teigland result.user_lksb = ua->user_lksb; 648597d0caeSDavid Teigland 649597d0caeSDavid Teigland /* FIXME: dlm1 provides for the user's bastparam/addr to not be updated 650597d0caeSDavid Teigland in a conversion unless the conversion is successful. See code 651597d0caeSDavid Teigland in dlm_user_convert() for updating ua from ua_tmp. OpenVMS, though, 652597d0caeSDavid Teigland notes that a new blocking AST address and parameter are set even if 653597d0caeSDavid Teigland the conversion fails, so maybe we should just do that. */ 654597d0caeSDavid Teigland 655597d0caeSDavid Teigland if (type == AST_BAST) { 656597d0caeSDavid Teigland result.user_astaddr = ua->bastaddr; 657597d0caeSDavid Teigland result.user_astparam = ua->bastparam; 658597d0caeSDavid Teigland result.bast_mode = bmode; 659597d0caeSDavid Teigland } else { 660597d0caeSDavid Teigland result.user_astaddr = ua->castaddr; 661597d0caeSDavid Teigland result.user_astparam = ua->castparam; 662597d0caeSDavid Teigland } 663597d0caeSDavid Teigland 664597d0caeSDavid Teigland #ifdef CONFIG_COMPAT 665597d0caeSDavid Teigland if (compat) 666597d0caeSDavid Teigland len = sizeof(struct dlm_lock_result32); 667597d0caeSDavid Teigland else 668597d0caeSDavid Teigland #endif 669597d0caeSDavid Teigland len = sizeof(struct dlm_lock_result); 670597d0caeSDavid Teigland struct_len = len; 671597d0caeSDavid Teigland 672597d0caeSDavid Teigland /* copy lvb to userspace if there is one, it's been updated, and 673597d0caeSDavid Teigland the user buffer has space for it */ 674597d0caeSDavid Teigland 675597d0caeSDavid Teigland if (ua->update_user_lvb && ua->lksb.sb_lvbptr && 676597d0caeSDavid Teigland count >= len + DLM_USER_LVB_LEN) { 677597d0caeSDavid Teigland if (copy_to_user(buf+len, ua->lksb.sb_lvbptr, 678597d0caeSDavid Teigland DLM_USER_LVB_LEN)) { 679597d0caeSDavid Teigland error = -EFAULT; 680597d0caeSDavid Teigland goto out; 681597d0caeSDavid Teigland } 682597d0caeSDavid Teigland 683597d0caeSDavid Teigland result.lvb_offset = len; 684597d0caeSDavid Teigland len += DLM_USER_LVB_LEN; 685597d0caeSDavid Teigland } 686597d0caeSDavid Teigland 687597d0caeSDavid Teigland result.length = len; 688597d0caeSDavid Teigland resultptr = &result; 689597d0caeSDavid Teigland #ifdef CONFIG_COMPAT 690597d0caeSDavid Teigland if (compat) { 691597d0caeSDavid Teigland compat_output(&result, &result32); 692597d0caeSDavid Teigland resultptr = &result32; 693597d0caeSDavid Teigland } 694597d0caeSDavid Teigland #endif 695597d0caeSDavid Teigland 696597d0caeSDavid Teigland if (copy_to_user(buf, resultptr, struct_len)) 697597d0caeSDavid Teigland error = -EFAULT; 698597d0caeSDavid Teigland else 699597d0caeSDavid Teigland error = len; 700597d0caeSDavid Teigland out: 701597d0caeSDavid Teigland return error; 702597d0caeSDavid Teigland } 703597d0caeSDavid Teigland 704597d0caeSDavid Teigland /* a read returns a single ast described in a struct dlm_lock_result */ 705597d0caeSDavid Teigland 706597d0caeSDavid Teigland static ssize_t device_read(struct file *file, char __user *buf, size_t count, 707597d0caeSDavid Teigland loff_t *ppos) 708597d0caeSDavid Teigland { 709597d0caeSDavid Teigland struct dlm_user_proc *proc = file->private_data; 710597d0caeSDavid Teigland struct dlm_lkb *lkb; 711597d0caeSDavid Teigland struct dlm_user_args *ua; 712597d0caeSDavid Teigland DECLARE_WAITQUEUE(wait, current); 713597d0caeSDavid Teigland int error, type=0, bmode=0, removed = 0; 714597d0caeSDavid Teigland 715597d0caeSDavid Teigland #ifdef CONFIG_COMPAT 716597d0caeSDavid Teigland if (count < sizeof(struct dlm_lock_result32)) 717597d0caeSDavid Teigland #else 718597d0caeSDavid Teigland if (count < sizeof(struct dlm_lock_result)) 719597d0caeSDavid Teigland #endif 720597d0caeSDavid Teigland return -EINVAL; 721597d0caeSDavid Teigland 722597d0caeSDavid Teigland /* do we really need this? can a read happen after a close? */ 723597d0caeSDavid Teigland if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags)) 724597d0caeSDavid Teigland return -EINVAL; 725597d0caeSDavid Teigland 726597d0caeSDavid Teigland spin_lock(&proc->asts_spin); 727597d0caeSDavid Teigland if (list_empty(&proc->asts)) { 728597d0caeSDavid Teigland if (file->f_flags & O_NONBLOCK) { 729597d0caeSDavid Teigland spin_unlock(&proc->asts_spin); 730597d0caeSDavid Teigland return -EAGAIN; 731597d0caeSDavid Teigland } 732597d0caeSDavid Teigland 733597d0caeSDavid Teigland add_wait_queue(&proc->wait, &wait); 734597d0caeSDavid Teigland 735597d0caeSDavid Teigland repeat: 736597d0caeSDavid Teigland set_current_state(TASK_INTERRUPTIBLE); 737597d0caeSDavid Teigland if (list_empty(&proc->asts) && !signal_pending(current)) { 738597d0caeSDavid Teigland spin_unlock(&proc->asts_spin); 739597d0caeSDavid Teigland schedule(); 740597d0caeSDavid Teigland spin_lock(&proc->asts_spin); 741597d0caeSDavid Teigland goto repeat; 742597d0caeSDavid Teigland } 743597d0caeSDavid Teigland set_current_state(TASK_RUNNING); 744597d0caeSDavid Teigland remove_wait_queue(&proc->wait, &wait); 745597d0caeSDavid Teigland 746597d0caeSDavid Teigland if (signal_pending(current)) { 747597d0caeSDavid Teigland spin_unlock(&proc->asts_spin); 748597d0caeSDavid Teigland return -ERESTARTSYS; 749597d0caeSDavid Teigland } 750597d0caeSDavid Teigland } 751597d0caeSDavid Teigland 752597d0caeSDavid Teigland if (list_empty(&proc->asts)) { 753597d0caeSDavid Teigland spin_unlock(&proc->asts_spin); 754597d0caeSDavid Teigland return -EAGAIN; 755597d0caeSDavid Teigland } 756597d0caeSDavid Teigland 757597d0caeSDavid Teigland /* there may be both completion and blocking asts to return for 758597d0caeSDavid Teigland the lkb, don't remove lkb from asts list unless no asts remain */ 759597d0caeSDavid Teigland 760597d0caeSDavid Teigland lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue); 761597d0caeSDavid Teigland 762597d0caeSDavid Teigland if (lkb->lkb_ast_type & AST_COMP) { 763597d0caeSDavid Teigland lkb->lkb_ast_type &= ~AST_COMP; 764597d0caeSDavid Teigland type = AST_COMP; 765597d0caeSDavid Teigland } else if (lkb->lkb_ast_type & AST_BAST) { 766597d0caeSDavid Teigland lkb->lkb_ast_type &= ~AST_BAST; 767597d0caeSDavid Teigland type = AST_BAST; 768597d0caeSDavid Teigland bmode = lkb->lkb_bastmode; 769597d0caeSDavid Teigland } 770597d0caeSDavid Teigland 771597d0caeSDavid Teigland if (!lkb->lkb_ast_type) { 772597d0caeSDavid Teigland list_del(&lkb->lkb_astqueue); 773597d0caeSDavid Teigland removed = 1; 774597d0caeSDavid Teigland } 775597d0caeSDavid Teigland spin_unlock(&proc->asts_spin); 776597d0caeSDavid Teigland 777597d0caeSDavid Teigland ua = (struct dlm_user_args *)lkb->lkb_astparam; 778597d0caeSDavid Teigland error = copy_result_to_user(ua, 779597d0caeSDavid Teigland test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags), 780597d0caeSDavid Teigland type, bmode, buf, count); 781597d0caeSDavid Teigland 782597d0caeSDavid Teigland /* removes reference for the proc->asts lists added by 783597d0caeSDavid Teigland dlm_user_add_ast() and may result in the lkb being freed */ 784597d0caeSDavid Teigland if (removed) 785597d0caeSDavid Teigland dlm_put_lkb(lkb); 786597d0caeSDavid Teigland 787597d0caeSDavid Teigland return error; 788597d0caeSDavid Teigland } 789597d0caeSDavid Teigland 790597d0caeSDavid Teigland static unsigned int device_poll(struct file *file, poll_table *wait) 791597d0caeSDavid Teigland { 792597d0caeSDavid Teigland struct dlm_user_proc *proc = file->private_data; 793597d0caeSDavid Teigland 794597d0caeSDavid Teigland poll_wait(file, &proc->wait, wait); 795597d0caeSDavid Teigland 796597d0caeSDavid Teigland spin_lock(&proc->asts_spin); 797597d0caeSDavid Teigland if (!list_empty(&proc->asts)) { 798597d0caeSDavid Teigland spin_unlock(&proc->asts_spin); 799597d0caeSDavid Teigland return POLLIN | POLLRDNORM; 800597d0caeSDavid Teigland } 801597d0caeSDavid Teigland spin_unlock(&proc->asts_spin); 802597d0caeSDavid Teigland return 0; 803597d0caeSDavid Teigland } 804597d0caeSDavid Teigland 805597d0caeSDavid Teigland static int ctl_device_open(struct inode *inode, struct file *file) 806597d0caeSDavid Teigland { 807597d0caeSDavid Teigland file->private_data = NULL; 808597d0caeSDavid Teigland return 0; 809597d0caeSDavid Teigland } 810597d0caeSDavid Teigland 811597d0caeSDavid Teigland static int ctl_device_close(struct inode *inode, struct file *file) 812597d0caeSDavid Teigland { 813597d0caeSDavid Teigland return 0; 814597d0caeSDavid Teigland } 815597d0caeSDavid Teigland 81600977a59SArjan van de Ven static const struct file_operations device_fops = { 817597d0caeSDavid Teigland .open = device_open, 818597d0caeSDavid Teigland .release = device_close, 819597d0caeSDavid Teigland .read = device_read, 820597d0caeSDavid Teigland .write = device_write, 821597d0caeSDavid Teigland .poll = device_poll, 822597d0caeSDavid Teigland .owner = THIS_MODULE, 823597d0caeSDavid Teigland }; 824597d0caeSDavid Teigland 82500977a59SArjan van de Ven static const struct file_operations ctl_device_fops = { 826597d0caeSDavid Teigland .open = ctl_device_open, 827597d0caeSDavid Teigland .release = ctl_device_close, 828597d0caeSDavid Teigland .write = device_write, 829597d0caeSDavid Teigland .owner = THIS_MODULE, 830597d0caeSDavid Teigland }; 831597d0caeSDavid Teigland 832597d0caeSDavid Teigland int dlm_user_init(void) 833597d0caeSDavid Teigland { 834597d0caeSDavid Teigland int error; 835597d0caeSDavid Teigland 836597d0caeSDavid Teigland ctl_device.name = "dlm-control"; 837597d0caeSDavid Teigland ctl_device.fops = &ctl_device_fops; 838597d0caeSDavid Teigland ctl_device.minor = MISC_DYNAMIC_MINOR; 839597d0caeSDavid Teigland 840597d0caeSDavid Teigland error = misc_register(&ctl_device); 841597d0caeSDavid Teigland if (error) 842597d0caeSDavid Teigland log_print("misc_register failed for control device"); 843597d0caeSDavid Teigland 844597d0caeSDavid Teigland return error; 845597d0caeSDavid Teigland } 846597d0caeSDavid Teigland 847597d0caeSDavid Teigland void dlm_user_exit(void) 848597d0caeSDavid Teigland { 849597d0caeSDavid Teigland misc_deregister(&ctl_device); 850597d0caeSDavid Teigland } 851597d0caeSDavid Teigland 852