📄 dlmglue.c
字号:
status = ocfs2_read_block(osb, bh->b_blocknr, &bh, 0, si->si_inode); if (status == 0) ocfs2_update_slot_info(si); ocfs2_complete_lock_res_refresh(lockres, status); if (status < 0) mlog_errno(status); }bail: mlog_exit(status); return status;}void ocfs2_super_unlock(struct ocfs2_super *osb, int ex){ int level = ex ? LKM_EXMODE : LKM_PRMODE; struct ocfs2_lock_res *lockres = &osb->osb_super_lockres; if (!ocfs2_mount_local(osb)) ocfs2_cluster_unlock(osb, lockres, level);}int ocfs2_rename_lock(struct ocfs2_super *osb){ int status; struct ocfs2_lock_res *lockres = &osb->osb_rename_lockres; if (ocfs2_is_hard_readonly(osb)) return -EROFS; if (ocfs2_mount_local(osb)) return 0; status = ocfs2_cluster_lock(osb, lockres, LKM_EXMODE, 0, 0); if (status < 0) mlog_errno(status); return status;}void ocfs2_rename_unlock(struct ocfs2_super *osb){ struct ocfs2_lock_res *lockres = &osb->osb_rename_lockres; if (!ocfs2_mount_local(osb)) ocfs2_cluster_unlock(osb, lockres, LKM_EXMODE);}int ocfs2_dentry_lock(struct dentry *dentry, int ex){ int ret; int level = ex ? LKM_EXMODE : LKM_PRMODE; struct ocfs2_dentry_lock *dl = dentry->d_fsdata; struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); BUG_ON(!dl); if (ocfs2_is_hard_readonly(osb)) return -EROFS; if (ocfs2_mount_local(osb)) return 0; ret = ocfs2_cluster_lock(osb, &dl->dl_lockres, level, 0, 0); if (ret < 0) mlog_errno(ret); return ret;}void ocfs2_dentry_unlock(struct dentry *dentry, int ex){ int level = ex ? LKM_EXMODE : LKM_PRMODE; struct ocfs2_dentry_lock *dl = dentry->d_fsdata; struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); if (!ocfs2_mount_local(osb)) ocfs2_cluster_unlock(osb, &dl->dl_lockres, level);}/* Reference counting of the dlm debug structure. We want this because * open references on the debug inodes can live on after a mount, so * we can't rely on the ocfs2_super to always exist. */static void ocfs2_dlm_debug_free(struct kref *kref){ struct ocfs2_dlm_debug *dlm_debug; dlm_debug = container_of(kref, struct ocfs2_dlm_debug, d_refcnt); kfree(dlm_debug);}void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug){ if (dlm_debug) kref_put(&dlm_debug->d_refcnt, ocfs2_dlm_debug_free);}static void ocfs2_get_dlm_debug(struct ocfs2_dlm_debug *debug){ kref_get(&debug->d_refcnt);}struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void){ struct ocfs2_dlm_debug *dlm_debug; dlm_debug = kmalloc(sizeof(struct ocfs2_dlm_debug), GFP_KERNEL); if (!dlm_debug) { mlog_errno(-ENOMEM); goto out; } kref_init(&dlm_debug->d_refcnt); INIT_LIST_HEAD(&dlm_debug->d_lockres_tracking); dlm_debug->d_locking_state = NULL;out: return dlm_debug;}/* Access to this is arbitrated for us via seq_file->sem. */struct ocfs2_dlm_seq_priv { struct ocfs2_dlm_debug *p_dlm_debug; struct ocfs2_lock_res p_iter_res; struct ocfs2_lock_res p_tmp_res;};static struct ocfs2_lock_res *ocfs2_dlm_next_res(struct ocfs2_lock_res *start, struct ocfs2_dlm_seq_priv *priv){ struct ocfs2_lock_res *iter, *ret = NULL; struct ocfs2_dlm_debug *dlm_debug = priv->p_dlm_debug; assert_spin_locked(&ocfs2_dlm_tracking_lock); list_for_each_entry(iter, &start->l_debug_list, l_debug_list) { /* discover the head of the list */ if (&iter->l_debug_list == &dlm_debug->d_lockres_tracking) { mlog(0, "End of list found, %p\n", ret); break; } /* We track our "dummy" iteration lockres' by a NULL * l_ops field. */ if (iter->l_ops != NULL) { ret = iter; break; } } return ret;}static void *ocfs2_dlm_seq_start(struct seq_file *m, loff_t *pos){ struct ocfs2_dlm_seq_priv *priv = m->private; struct ocfs2_lock_res *iter; spin_lock(&ocfs2_dlm_tracking_lock); iter = ocfs2_dlm_next_res(&priv->p_iter_res, priv); if (iter) { /* Since lockres' have the lifetime of their container * (which can be inodes, ocfs2_supers, etc) we want to * copy this out to a temporary lockres while still * under the spinlock. Obviously after this we can't * trust any pointers on the copy returned, but that's * ok as the information we want isn't typically held * in them. */ priv->p_tmp_res = *iter; iter = &priv->p_tmp_res; } spin_unlock(&ocfs2_dlm_tracking_lock); return iter;}static void ocfs2_dlm_seq_stop(struct seq_file *m, void *v){}static void *ocfs2_dlm_seq_next(struct seq_file *m, void *v, loff_t *pos){ struct ocfs2_dlm_seq_priv *priv = m->private; struct ocfs2_lock_res *iter = v; struct ocfs2_lock_res *dummy = &priv->p_iter_res; spin_lock(&ocfs2_dlm_tracking_lock); iter = ocfs2_dlm_next_res(iter, priv); list_del_init(&dummy->l_debug_list); if (iter) { list_add(&dummy->l_debug_list, &iter->l_debug_list); priv->p_tmp_res = *iter; iter = &priv->p_tmp_res; } spin_unlock(&ocfs2_dlm_tracking_lock); return iter;}/* So that debugfs.ocfs2 can determine which format is being used */#define OCFS2_DLM_DEBUG_STR_VERSION 1static int ocfs2_dlm_seq_show(struct seq_file *m, void *v){ int i; char *lvb; struct ocfs2_lock_res *lockres = v; if (!lockres) return -EINVAL; seq_printf(m, "0x%x\t", OCFS2_DLM_DEBUG_STR_VERSION); if (lockres->l_type == OCFS2_LOCK_TYPE_DENTRY) seq_printf(m, "%.*s%08x\t", OCFS2_DENTRY_LOCK_INO_START - 1, lockres->l_name, (unsigned int)ocfs2_get_dentry_lock_ino(lockres)); else seq_printf(m, "%.*s\t", OCFS2_LOCK_ID_MAX_LEN, lockres->l_name); seq_printf(m, "%d\t" "0x%lx\t" "0x%x\t" "0x%x\t" "%u\t" "%u\t" "%d\t" "%d\t", lockres->l_level, lockres->l_flags, lockres->l_action, lockres->l_unlock_action, lockres->l_ro_holders, lockres->l_ex_holders, lockres->l_requested, lockres->l_blocking); /* Dump the raw LVB */ lvb = lockres->l_lksb.lvb; for(i = 0; i < DLM_LVB_LEN; i++) seq_printf(m, "0x%x\t", lvb[i]); /* End the line */ seq_printf(m, "\n"); return 0;}static struct seq_operations ocfs2_dlm_seq_ops = { .start = ocfs2_dlm_seq_start, .stop = ocfs2_dlm_seq_stop, .next = ocfs2_dlm_seq_next, .show = ocfs2_dlm_seq_show,};static int ocfs2_dlm_debug_release(struct inode *inode, struct file *file){ struct seq_file *seq = (struct seq_file *) file->private_data; struct ocfs2_dlm_seq_priv *priv = seq->private; struct ocfs2_lock_res *res = &priv->p_iter_res; ocfs2_remove_lockres_tracking(res); ocfs2_put_dlm_debug(priv->p_dlm_debug); return seq_release_private(inode, file);}static int ocfs2_dlm_debug_open(struct inode *inode, struct file *file){ int ret; struct ocfs2_dlm_seq_priv *priv; struct seq_file *seq; struct ocfs2_super *osb; priv = kzalloc(sizeof(struct ocfs2_dlm_seq_priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; mlog_errno(ret); goto out; } osb = inode->i_private; ocfs2_get_dlm_debug(osb->osb_dlm_debug); priv->p_dlm_debug = osb->osb_dlm_debug; INIT_LIST_HEAD(&priv->p_iter_res.l_debug_list); ret = seq_open(file, &ocfs2_dlm_seq_ops); if (ret) { kfree(priv); mlog_errno(ret); goto out; } seq = (struct seq_file *) file->private_data; seq->private = priv; ocfs2_add_lockres_tracking(&priv->p_iter_res, priv->p_dlm_debug);out: return ret;}static const struct file_operations ocfs2_dlm_debug_fops = { .open = ocfs2_dlm_debug_open, .release = ocfs2_dlm_debug_release, .read = seq_read, .llseek = seq_lseek,};static int ocfs2_dlm_init_debug(struct ocfs2_super *osb){ int ret = 0; struct ocfs2_dlm_debug *dlm_debug = osb->osb_dlm_debug; dlm_debug->d_locking_state = debugfs_create_file("locking_state", S_IFREG|S_IRUSR, osb->osb_debug_root, osb, &ocfs2_dlm_debug_fops); if (!dlm_debug->d_locking_state) { ret = -EINVAL; mlog(ML_ERROR, "Unable to create locking state debugfs file.\n"); goto out; } ocfs2_get_dlm_debug(dlm_debug);out: return ret;}static void ocfs2_dlm_shutdown_debug(struct ocfs2_super *osb){ struct ocfs2_dlm_debug *dlm_debug = osb->osb_dlm_debug; if (dlm_debug) { debugfs_remove(dlm_debug->d_locking_state); ocfs2_put_dlm_debug(dlm_debug); }}int ocfs2_dlm_init(struct ocfs2_super *osb){ int status = 0; u32 dlm_key; struct dlm_ctxt *dlm = NULL; mlog_entry_void(); if (ocfs2_mount_local(osb)) goto local; status = ocfs2_dlm_init_debug(osb); if (status < 0) { mlog_errno(status); goto bail; } /* launch vote thread */ osb->vote_task = kthread_run(ocfs2_vote_thread, osb, "ocfs2vote"); if (IS_ERR(osb->vote_task)) { status = PTR_ERR(osb->vote_task); osb->vote_task = NULL; mlog_errno(status); goto bail; } /* used by the dlm code to make message headers unique, each * node in this domain must agree on this. */ dlm_key = crc32_le(0, osb->uuid_str, strlen(osb->uuid_str)); /* for now, uuid == domain */ dlm = dlm_register_domain(osb->uuid_str, dlm_key); if (IS_ERR(dlm)) { status = PTR_ERR(dlm); mlog_errno(status); goto bail; } dlm_register_eviction_cb(dlm, &osb->osb_eviction_cb);local: ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb); ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb); osb->dlm = dlm; status = 0;bail: if (status < 0) { ocfs2_dlm_shutdown_debug(osb); if (osb->vote_task) kthread_stop(osb->vote_task); } mlog_exit(status); return status;}void ocfs2_dlm_shutdown(struct ocfs2_super *osb){ mlog_entry_void(); dlm_unregister_eviction_cb(&osb->osb_eviction_cb); ocfs2_drop_osb_locks(osb); if (osb->vote_task) { kthread_stop(osb->vote_task); osb->vote_task = NULL; } ocfs2_lock_res_free(&osb->osb_super_lockres); ocfs2_lock_res_free(&osb->osb_rename_lockres); dlm_unregister_domain(osb->dlm); osb->dlm = NULL; ocfs2_dlm_shutdown_debug(osb); mlog_exit_void();}static void ocfs2_unlock_ast(void *opaque, enum dlm_status status){ struct ocfs2_lock_res *lockres = opaque; unsigned long flags; mlog_entry_void(); mlog(0, "UNLOCK AST called on lock %s, action = %d\n", lockres->l_name, lockres->l_unlock_action); spin_lock_irqsave(&lockres->l_lock, flags); /* We tried to cancel a convert request, but it was already * granted. All we want to do here is clear our unlock * state. The wake_up call done at the bottom is redundant * (ocfs2_prepare_cancel_convert doesn't sleep on this) but doesn't * hurt anything anyway */ if (status == DLM_CANCELGRANT && lockres->l_unlock_action == OCFS2_UNLOCK_CANCEL_CONVERT) { mlog(0, "Got cancelgrant for %s\n", lockres->l_name); /* We don't clear the busy flag in this case as it * should have been cleared by the ast which the dlm * has called. */ goto complete_unlock; } if (status != DLM_NORMAL) { mlog(ML_ERROR, "Dlm passes status %d for lock %s, " "unlock_action %d\n", status, lockres->l_name, lockres->l_unlock_action); spin_unlock_irqrestore(&lockres->l_lock, flags); return; } switch(lockres->l_unlock_action) { case OCFS2_UNLOCK_CANCEL_CONVERT: mlog(0, "Cancel convert success for %s\n", lockres->l_name); lockres->l_action = OCFS2_AST_INVALID; break; case OCFS2_UNLOCK_DROP_LOCK: lockres->l_level = LKM_IVMODE; break; default: BUG(); } lockres_clear_flags(lockres, OCFS2_LOCK_BUSY);complete_unlock: lockres->l_unlock_action = OCFS2_UNLOCK_INVALID; spin_unlock_irqrestore(&lockres->l_lock, flags); wake_up(&lockres->l_event); mlog_exit_void();}static int ocfs2_drop_lock(struct ocfs2_super *osb, struct ocfs2_lock_res *lockres){ enum dlm_status status; unsigned long flags; int lkm_flags = 0; /* We didn't get anywhere near actually using this lockres. */ if (!(lockres->l_flags & OCFS2_LOCK_INITI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -