📄 dlmglue.c
字号:
} status = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, ret_bh, OCFS2_BH_CACHED, inode); if (status < 0) mlog_errno(status); return status;}/* * returns < 0 error if the callback will never be called, otherwise * the result of the lock will be communicated via the callback. */int ocfs2_meta_lock_full(struct inode *inode, struct ocfs2_journal_handle *handle, struct buffer_head **ret_bh, int ex, int flags, ocfs2_lock_callback cb, unsigned long cb_data){ int status, level, dlm_flags, acquired; struct ocfs2_lock_res *lockres = NULL; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct buffer_head *local_bh = NULL; BUG_ON(!inode); mlog_entry_void(); mlog(0, "inode %"MLFu64", take %s META lock\n", OCFS2_I(inode)->ip_blkno, ex ? "EXMODE" : "PRMODE"); status = 0; acquired = 0; /* We'll allow faking a readonly metadata lock for * rodevices. */ if (ocfs2_is_hard_readonly(osb)) { if (ex) status = -EROFS; goto bail; } if (ocfs2_mount_local(osb)) goto local; if (!(flags & OCFS2_META_LOCK_RECOVERY)) wait_event(osb->recovery_event, ocfs2_node_map_is_empty(osb, &osb->recovery_map)); lockres = &OCFS2_I(inode)->ip_meta_lockres; level = ex ? LKM_EXMODE : LKM_PRMODE; dlm_flags = 0; if (flags & OCFS2_META_LOCK_NOQUEUE) dlm_flags |= LKM_NOQUEUE; status = ocfs2_cluster_lock(osb, lockres, level, dlm_flags, cb, cb_data); if (status < 0) { if (status != -EAGAIN && status != -EIOCBRETRY) mlog_errno(status); goto bail; } /* Notify the error cleanup path to drop the cluster lock. */ acquired = 1; /* We wait twice because a node may have died while we were in * the lower dlm layers. The second time though, we've * committed to owning this lock so we don't allow signals to * abort the operation. */ if (!(flags & OCFS2_META_LOCK_RECOVERY)) wait_event(osb->recovery_event, ocfs2_node_map_is_empty(osb, &osb->recovery_map));local: /* This is fun. The caller may want a bh back, or it may * not. ocfs2_meta_lock_update definitely wants one in, but * may or may not read one, depending on what's in the * LVB. The result of all of this is that we've *only* gone to * disk if we have to, so the complexity is worthwhile. */ status = ocfs2_meta_lock_update(inode, &local_bh); if (status < 0) { if (status != -ENOENT) mlog_errno(status); goto bail; } if (ret_bh) { status = ocfs2_assign_bh(inode, ret_bh, local_bh); if (status < 0) { mlog_errno(status); goto bail; } } if (handle) { status = ocfs2_handle_add_lock(handle, inode); if (status < 0) mlog_errno(status); }bail: if (status < 0) { if (ret_bh && (*ret_bh)) { brelse(*ret_bh); *ret_bh = NULL; } if (acquired) ocfs2_meta_unlock(inode, ex); } if (local_bh) brelse(local_bh); mlog_exit(status); return status;}void ocfs2_meta_unlock(struct inode *inode, int ex){ int level = ex ? LKM_EXMODE : LKM_PRMODE; struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_meta_lockres; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); mlog_entry_void(); mlog(0, "inode %"MLFu64" drop %s META lock\n", OCFS2_I(inode)->ip_blkno, ex ? "EXMODE" : "PRMODE"); if (!ocfs2_is_hard_readonly(osb) && !ocfs2_mount_local(osb)) ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level); mlog_exit_void();}int ocfs2_super_lock(struct ocfs2_super *osb, int ex){ int status; int level = ex ? LKM_EXMODE : LKM_PRMODE; struct ocfs2_lock_res *lockres = &osb->osb_super_lockres; struct buffer_head *bh; struct ocfs2_slot_info *si = osb->slot_info; mlog_entry_void(); if (ocfs2_is_hard_readonly(osb)) return -EROFS; if (ocfs2_mount_local(osb)) return 0; status = ocfs2_cluster_lock(osb, lockres, level, 0, NULL, 0); if (status < 0) { mlog_errno(status); goto bail; } /* The super block lock path is really in the best position to * know when resources covered by the lock need to be * refreshed, so we do it here. Of course, making sense of * everything is up to the caller :) */ status = ocfs2_should_refresh_lock_res(lockres); if (status < 0) { mlog_errno(status); goto bail; } if (status) { bh = si->si_bh; 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, NULL, 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);}/* 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, ocfs2_dlm_debug_free); 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" "%.*s\t" "%d\t" "0x%lx\t" "0x%x\t" "0x%x\t" "%u\t" "%u\t" "%d\t" "%d\t", OCFS2_DLM_DEBUG_STR_VERSION, OCFS2_LOCK_ID_MAX_LEN, lockres->l_name, 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; }#ifdef INODE_HAS_PRIVATE osb = inode->i_private;#else osb = (struct ocfs2_super *) inode->u.generic_ip;#endif 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 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; 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -