From 7242ccff16d6adfa273b2d2fe8d99b8bd615b1d3 Mon Sep 17 00:00:00 2001 From: almalinux-bot-kernel Date: Wed, 22 Apr 2026 05:02:39 +0000 Subject: [PATCH] Import of kernel-4.18.0-553.120.1.el8_10 --- Makefile.rhelver | 2 +- arch/x86/kvm/x86.c | 40 +++++++--- drivers/md/md-cluster.c | 4 +- drivers/s390/block/dasd_eckd.c | 24 ++++++ drivers/s390/virtio/virtio_ccw.c | 4 + drivers/scsi/qla2xxx/qla_nvme.c | 2 +- fs/dlm/config.c | 133 +++++++++++++++++++++++++------ fs/dlm/config.h | 4 +- fs/dlm/lock.c | 20 +---- fs/dlm/lockspace.c | 63 +++++++-------- fs/dlm/member.c | 29 +++++-- fs/dlm/user.c | 6 +- fs/gfs2/aops.c | 10 +-- fs/gfs2/glops.c | 8 +- fs/gfs2/lock_dlm.c | 4 +- fs/gfs2/log.c | 12 +-- fs/gfs2/log.h | 24 ------ fs/gfs2/lops.c | 16 ++-- fs/gfs2/meta_io.c | 8 +- fs/gfs2/super.c | 33 +++++++- fs/gfs2/trans.c | 45 ++++++----- fs/ocfs2/stack_user.c | 2 +- include/linux/dlm.h | 33 +++++++- sound/drivers/aloop.c | 122 +++++++++++++++++----------- 24 files changed, 419 insertions(+), 229 deletions(-) diff --git a/Makefile.rhelver b/Makefile.rhelver index 9bd8c8fee1..0cb754bd33 100644 --- a/Makefile.rhelver +++ b/Makefile.rhelver @@ -12,7 +12,7 @@ RHEL_MINOR = 10 # # Use this spot to avoid future merge conflicts. # Do not trim this comment. -RHEL_RELEASE = 553.117.1 +RHEL_RELEASE = 553.120.1 # # ZSTREAM diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f195373052..80ccad9fca 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -814,6 +814,13 @@ bool kvm_require_dr(struct kvm_vcpu *vcpu, int dr) } EXPORT_SYMBOL_GPL(kvm_require_dr); +static bool kvm_pv_async_pf_enabled(struct kvm_vcpu *vcpu) +{ + u64 mask = KVM_ASYNC_PF_ENABLED | KVM_ASYNC_PF_DELIVERY_AS_INT; + + return (vcpu->arch.apf.msr_en_val & mask) == mask; +} + static inline u64 pdptr_rsvd_bits(struct kvm_vcpu *vcpu) { return vcpu->arch.reserved_gpa_bits | rsvd_bits(5, 8) | rsvd_bits(1, 2); @@ -872,15 +879,20 @@ EXPORT_SYMBOL_GPL(load_pdptrs); void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned long cr0) { if ((cr0 ^ old_cr0) & X86_CR0_PG) { - kvm_clear_async_pf_completion_queue(vcpu); - kvm_async_pf_hash_reset(vcpu); - /* * Clearing CR0.PG is defined to flush the TLB from the guest's * perspective. */ if (!(cr0 & X86_CR0_PG)) kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu); + /* + * Check for async #PF completion events when enabling paging, + * as the vCPU may have previously encountered async #PFs (it's + * entirely legal for the guest to toggle paging on/off without + * waiting for the async #PF queue to drain). + */ + else if (kvm_pv_async_pf_enabled(vcpu)) + kvm_make_request(KVM_REQ_APF_READY, vcpu); } if ((cr0 ^ old_cr0) & KVM_MMU_CR0_ROLE_BITS) @@ -3246,13 +3258,6 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 0; } -static inline bool kvm_pv_async_pf_enabled(struct kvm_vcpu *vcpu) -{ - u64 mask = KVM_ASYNC_PF_ENABLED | KVM_ASYNC_PF_DELIVERY_AS_INT; - - return (vcpu->arch.apf.msr_en_val & mask) == mask; -} - static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data) { gpa_t gpa = data & ~0x3f; @@ -3679,7 +3684,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF_INT)) return 1; if (data & 0x1) { - vcpu->arch.apf.pageready_pending = false; + /* + * Pairs with the smp_mb__after_atomic() in + * kvm_arch_async_page_present_queued(). + */ + smp_store_mb(vcpu->arch.apf.pageready_pending, false); + kvm_check_async_pf_completion(vcpu); } break; @@ -12323,7 +12333,7 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, if ((work->wakeup_all || work->notpresent_injected) && kvm_pv_async_pf_enabled(vcpu) && !apf_put_user_ready(vcpu, work->arch.token)) { - vcpu->arch.apf.pageready_pending = true; + WRITE_ONCE(vcpu->arch.apf.pageready_pending, true); kvm_apic_set_irq(vcpu, &irq, NULL); } @@ -12334,7 +12344,11 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, void kvm_arch_async_page_present_queued(struct kvm_vcpu *vcpu) { kvm_make_request(KVM_REQ_APF_READY, vcpu); - if (!vcpu->arch.apf.pageready_pending) + + /* Pairs with smp_store_mb() in kvm_set_msr_common(). */ + smp_mb__after_atomic(); + + if (!READ_ONCE(vcpu->arch.apf.pageready_pending)) kvm_vcpu_kick(vcpu); } diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 13b8cb3e01..46a437818d 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -962,7 +962,7 @@ err: lockres_free(cinfo->resync_lockres); lockres_free(cinfo->bitmap_lockres); if (cinfo->lockspace) - dlm_release_lockspace(cinfo->lockspace, 2); + dlm_release_lockspace(cinfo->lockspace, DLM_RELEASE_NORMAL); mddev->cluster_info = NULL; kfree(cinfo); return ret; @@ -1025,7 +1025,7 @@ static int leave(struct mddev *mddev) lockres_free(cinfo->resync_lockres); lockres_free(cinfo->bitmap_lockres); unlock_all_bitmaps(mddev); - dlm_release_lockspace(cinfo->lockspace, 2); + dlm_release_lockspace(cinfo->lockspace, DLM_RELEASE_NORMAL); kfree(cinfo); return 0; } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 575d22dbee..93a882376b 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -6285,10 +6285,12 @@ static void copy_pair_set_active(struct dasd_copy_relation *copy, char *new_busi static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid, char *sec_busid) { + struct dasd_eckd_private *prim_priv, *sec_priv; struct dasd_device *primary, *secondary; struct dasd_copy_relation *copy; struct dasd_block *block; struct gendisk *gdp; + int rc; copy = device->copy; if (!copy) @@ -6304,6 +6306,9 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid if (!secondary) return DASD_COPYPAIRSWAP_SECONDARY; + prim_priv = primary->private; + sec_priv = secondary->private; + /* * usually the device should be quiesced for swap * for paranoia stop device and requeue requests again @@ -6323,6 +6328,25 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid /* swap blocklayer device link */ gdp = block->gdp; dasd_add_link_to_gendisk(gdp, secondary); + rc = device_move(disk_to_dev(gdp), &secondary->cdev->dev, DPM_ORDER_NONE); + if (rc) { + dev_err(&primary->cdev->dev, + "copy_pair_swap: moving blockdevice parent %s->%s failed (%d)\n", + dev_name(&primary->cdev->dev), + dev_name(&secondary->cdev->dev), rc); + } + + if (primary->stopped & DASD_STOPPED_QUIESCE) { + dasd_device_set_stop_bits(secondary, DASD_STOPPED_QUIESCE); + dasd_device_remove_stop_bits(primary, DASD_STOPPED_QUIESCE); + } + + /* + * The secondary device never got through format detection, but since it + * is a copy of the primary device, the format is exactly the same; + * therefore, the detected layout can simply be copied. + */ + sec_priv->uses_cdl = prim_priv->uses_cdl; /* re-enable device */ dasd_device_remove_stop_bits(primary, DASD_STOPPED_PPRC); diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 9a525d410e..c0e79fc187 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -58,6 +58,8 @@ struct virtio_ccw_device { struct virtio_device vdev; __u8 config[VIRTIO_CCW_CONFIG_SIZE]; struct ccw_device *cdev; + /* we make cdev->dev.dma_parms point to this */ + struct device_dma_parameters dma_parms; __u32 curr_io; int err; unsigned int revision; /* Transport revision */ @@ -1206,6 +1208,7 @@ static int virtio_ccw_offline(struct ccw_device *cdev) unregister_virtio_device(&vcdev->vdev); spin_lock_irqsave(get_ccwdev_lock(cdev), flags); dev_set_drvdata(&cdev->dev, NULL); + cdev->dev.dma_parms = NULL; spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); return 0; } @@ -1270,6 +1273,7 @@ static int virtio_ccw_online(struct ccw_device *cdev) } vcdev->vdev.dev.parent = &cdev->dev; vcdev->cdev = cdev; + cdev->dev.dma_parms = &vcdev->dma_parms; vcdev->dma_area = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*vcdev->dma_area)); if (!vcdev->dma_area) { diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 34b5211ac5..90fb0a7a84 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -1295,7 +1295,7 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) a.reason = FCNVME_RJT_RC_LOGIC; a.explanation = FCNVME_RJT_EXP_NONE; xmt_reject = true; - kfree(item); + qla24xx_free_purex_item(item); goto out; } diff --git a/fs/dlm/config.c b/fs/dlm/config.c index 6cf04563f6..ed52e36f89 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c @@ -25,9 +25,10 @@ #include "lowcomms.h" /* - * /config/dlm//spaces//nodes//nodeid + * /config/dlm//spaces//nodes//nodeid (refers to ) * /config/dlm//spaces//nodes//weight - * /config/dlm//comms//nodeid + * /config/dlm//spaces//nodes//release_recover + * /config/dlm//comms//nodeid (refers to ) * /config/dlm//comms//local * /config/dlm//comms//addr (write only) * /config/dlm//comms//addr_list (read only) @@ -208,6 +209,7 @@ enum { enum { NODE_ATTR_NODEID = 0, NODE_ATTR_WEIGHT, + NODE_ATTR_RELEASE_RECOVER, }; struct dlm_clusters { @@ -221,6 +223,8 @@ struct dlm_spaces { struct dlm_space { struct config_group group; struct list_head members; + struct list_head members_gone; + int members_gone_count; struct mutex members_lock; int members_count; }; @@ -250,6 +254,14 @@ struct dlm_node { int weight; int new; int comm_seq; /* copy of cm->seq when nd->nodeid is set */ + unsigned int release_recover; +}; + +struct dlm_member_gone { + int nodeid; + unsigned int release_recover; + + struct list_head list; /* space->members_gone */ }; static struct configfs_group_operations clusters_ops = { @@ -430,6 +442,7 @@ static struct config_group *make_space(struct config_group *g, const char *name) configfs_add_default_group(&nds->ns_group, &sp->group); INIT_LIST_HEAD(&sp->members); + INIT_LIST_HEAD(&sp->members_gone); mutex_init(&sp->members_lock); sp->members_count = 0; return &sp->group; @@ -459,6 +472,12 @@ static void release_space(struct config_item *i) static struct config_item *make_comm(struct config_group *g, const char *name) { struct dlm_comm *cm; + unsigned int nodeid; + int rv; + + rv = kstrtouint(name, 0, &nodeid); + if (rv) + return ERR_PTR(rv); cm = kzalloc(sizeof(struct dlm_comm), GFP_NOFS); if (!cm) @@ -470,7 +489,7 @@ static struct config_item *make_comm(struct config_group *g, const char *name) if (!cm->seq) cm->seq = dlm_comm_count++; - cm->nodeid = -1; + cm->nodeid = nodeid; cm->local = 0; cm->addr_count = 0; cm->mark = 0; @@ -497,16 +516,25 @@ static void release_comm(struct config_item *i) static struct config_item *make_node(struct config_group *g, const char *name) { struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent); + unsigned int nodeid; struct dlm_node *nd; + uint32_t seq = 0; + int rv; + + rv = kstrtouint(name, 0, &nodeid); + if (rv) + return ERR_PTR(rv); nd = kzalloc(sizeof(struct dlm_node), GFP_NOFS); if (!nd) return ERR_PTR(-ENOMEM); config_item_init_type_name(&nd->item, name, &node_type); - nd->nodeid = -1; + nd->nodeid = nodeid; nd->weight = 1; /* default weight of 1 if none is set */ nd->new = 1; /* set to 0 once it's been read by dlm_nodeid_list() */ + dlm_comm_seq(nodeid, &seq, true); + nd->comm_seq = seq; mutex_lock(&sp->members_lock); list_add(&nd->list, &sp->members); @@ -520,10 +548,20 @@ static void drop_node(struct config_group *g, struct config_item *i) { struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent); struct dlm_node *nd = config_item_to_node(i); + struct dlm_member_gone *mb_gone; + + mb_gone = kzalloc(sizeof(*mb_gone), GFP_KERNEL); + if (!mb_gone) + return; mutex_lock(&sp->members_lock); list_del(&nd->list); sp->members_count--; + + mb_gone->nodeid = nd->nodeid; + mb_gone->release_recover = nd->release_recover; + list_add(&mb_gone->list, &sp->members_gone); + sp->members_gone_count++; mutex_unlock(&sp->members_lock); config_item_put(i); @@ -564,16 +602,19 @@ void dlm_config_exit(void) static ssize_t comm_nodeid_show(struct config_item *item, char *buf) { - return sprintf(buf, "%d\n", config_item_to_comm(item)->nodeid); + unsigned int nodeid; + int rv; + + rv = kstrtouint(config_item_name(item), 0, &nodeid); + if (WARN_ON(rv)) + return rv; + + return sprintf(buf, "%u\n", nodeid); } static ssize_t comm_nodeid_store(struct config_item *item, const char *buf, size_t len) { - int rc = kstrtoint(buf, 0, &config_item_to_comm(item)->nodeid); - - if (rc) - return rc; return len; } @@ -714,20 +755,19 @@ static struct configfs_attribute *comm_attrs[] = { static ssize_t node_nodeid_show(struct config_item *item, char *buf) { - return sprintf(buf, "%d\n", config_item_to_node(item)->nodeid); + unsigned int nodeid; + int rv; + + rv = kstrtouint(config_item_name(item), 0, &nodeid); + if (WARN_ON(rv)) + return rv; + + return sprintf(buf, "%u\n", nodeid); } static ssize_t node_nodeid_store(struct config_item *item, const char *buf, size_t len) { - struct dlm_node *nd = config_item_to_node(item); - uint32_t seq = 0; - int rc = kstrtoint(buf, 0, &nd->nodeid); - - if (rc) - return rc; - dlm_comm_seq(nd->nodeid, &seq); - nd->comm_seq = seq; return len; } @@ -746,12 +786,34 @@ static ssize_t node_weight_store(struct config_item *item, const char *buf, return len; } +static ssize_t node_release_recover_show(struct config_item *item, char *buf) +{ + struct dlm_node *n = config_item_to_node(item); + + return sprintf(buf, "%u\n", n->release_recover); +} + +static ssize_t node_release_recover_store(struct config_item *item, + const char *buf, size_t len) +{ + struct dlm_node *n = config_item_to_node(item); + int rc; + + rc = kstrtouint(buf, 0, &n->release_recover); + if (rc) + return rc; + + return len; +} + CONFIGFS_ATTR(node_, nodeid); CONFIGFS_ATTR(node_, weight); +CONFIGFS_ATTR(node_, release_recover); static struct configfs_attribute *node_attrs[] = { [NODE_ATTR_NODEID] = &node_attr_nodeid, [NODE_ATTR_WEIGHT] = &node_attr_weight, + [NODE_ATTR_RELEASE_RECOVER] = &node_attr_release_recover, NULL, }; @@ -787,7 +849,7 @@ static struct dlm_comm *get_comm(int nodeid) if (!comm_list) return NULL; - mutex_lock(&clusters_root.subsys.su_mutex); + WARN_ON_ONCE(!mutex_is_locked(&clusters_root.subsys.su_mutex)); list_for_each_entry(i, &comm_list->cg_children, ci_entry) { cm = config_item_to_comm(i); @@ -798,7 +860,6 @@ static struct dlm_comm *get_comm(int nodeid) config_item_get(i); break; } - mutex_unlock(&clusters_root.subsys.su_mutex); if (!found) cm = NULL; @@ -814,9 +875,10 @@ static void put_comm(struct dlm_comm *cm) int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out, int *count_out) { + struct dlm_member_gone *mb_gone, *mb_safe; + struct dlm_config_node *nodes, *node; struct dlm_space *sp; struct dlm_node *nd; - struct dlm_config_node *nodes, *node; int rv, count; sp = get_space(lsname); @@ -830,7 +892,7 @@ int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out, goto out; } - count = sp->members_count; + count = sp->members_count + sp->members_gone_count; nodes = kcalloc(count, sizeof(struct dlm_config_node), GFP_NOFS); if (!nodes) { @@ -849,6 +911,20 @@ int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out, nd->new = 0; } + /* we delay the remove on nodes until here as configfs does + * not support addtional attributes for rmdir(). + */ + list_for_each_entry_safe(mb_gone, mb_safe, &sp->members_gone, list) { + node->nodeid = mb_gone->nodeid; + node->release_recover = mb_gone->release_recover; + node->gone = true; + node++; + + list_del(&mb_gone->list); + sp->members_gone_count--; + kfree(mb_gone); + } + *count_out = count; *nodes_out = nodes; rv = 0; @@ -858,11 +934,20 @@ int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out, return rv; } -int dlm_comm_seq(int nodeid, uint32_t *seq) +int dlm_comm_seq(int nodeid, uint32_t *seq, bool locked) { - struct dlm_comm *cm = get_comm(nodeid); + struct dlm_comm *cm; + + if (locked) { + cm = get_comm(nodeid); + } else { + mutex_lock(&clusters_root.subsys.su_mutex); + cm = get_comm(nodeid); + mutex_unlock(&clusters_root.subsys.su_mutex); + } if (!cm) return -EEXIST; + *seq = cm->seq; put_comm(cm); return 0; diff --git a/fs/dlm/config.h b/fs/dlm/config.h index 3b25c975e4..a56c3a556a 100644 --- a/fs/dlm/config.h +++ b/fs/dlm/config.h @@ -17,8 +17,10 @@ struct dlm_config_node { int nodeid; int weight; + bool gone; int new; uint32_t comm_seq; + unsigned int release_recover; }; #define DLM_MAX_ADDR_COUNT 3 @@ -47,7 +49,7 @@ int dlm_config_init(void); void dlm_config_exit(void); int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out, int *count_out); -int dlm_comm_seq(int nodeid, uint32_t *seq); +int dlm_comm_seq(int nodeid, uint32_t *seq, bool locked); int dlm_our_nodeid(void); int dlm_our_addr(struct sockaddr_storage *addr, int num); diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 6a36bae143..f376768380 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -5110,26 +5110,8 @@ void dlm_receive_buffer(union dlm_packet *p, int nodeid) static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb, struct dlm_message *ms_stub) { - if (middle_conversion(lkb)) { - log_rinfo(ls, "%s %x middle convert in progress", __func__, - lkb->lkb_id); - - /* We sent this lock to the new master. The new master will - * tell us when it's granted. We no longer need a reply, so - * use a fake reply to put the lkb into the right state. - */ - hold_lkb(lkb); - memset(ms_stub, 0, sizeof(struct dlm_message)); - ms_stub->m_flags = DLM_IFL_STUB_MS; - ms_stub->m_type = DLM_MSG_CONVERT_REPLY; - ms_stub->m_result = -EINPROGRESS; - ms_stub->m_header.h_nodeid = lkb->lkb_nodeid; - _receive_convert_reply(lkb, ms_stub); - unhold_lkb(lkb); - - } else if (lkb->lkb_rqmode >= lkb->lkb_grmode) { + if (middle_conversion(lkb) || lkb->lkb_rqmode >= lkb->lkb_grmode) lkb->lkb_flags |= DLM_IFL_RESEND; - } /* lkb->lkb_rqmode < lkb->lkb_grmode shouldn't happen since down conversions are async; there's no reply from the remote master */ diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 5ba94be006..d1dedc6d02 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -196,34 +196,29 @@ static struct kobj_type dlm_ktype = { static struct kset *dlm_kset; -static int do_uevent(struct dlm_ls *ls, int in) +static int do_uevent(struct dlm_ls *ls, int in, unsigned int release_recover) { - int error; + char message[512] = {}; + char *envp[] = { message, NULL }; - if (in) + if (in) { kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE); - else - kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE); + } else { + snprintf(message, 511, "RELEASE_RECOVER=%u", release_recover); + kobject_uevent_env(&ls->ls_kobj, KOBJ_OFFLINE, envp); + } log_rinfo(ls, "%s the lockspace group...", in ? "joining" : "leaving"); /* dlm_controld will see the uevent, do the necessary group management and then write to sysfs to wake us */ - error = wait_event_interruptible(ls->ls_uevent_wait, - test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags)); + wait_event(ls->ls_uevent_wait, + test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags)); - log_rinfo(ls, "group event done %d %d", error, ls->ls_uevent_result); + log_rinfo(ls, "group event done %d", ls->ls_uevent_result); - if (error) - goto out; - - error = ls->ls_uevent_result; - out: - if (error) - log_error(ls, "group %s failed %d %d", in ? "join" : "leave", - error, ls->ls_uevent_result); - return error; + return ls->ls_uevent_result; } static int dlm_uevent(struct kset *kset, struct kobject *kobj, @@ -649,8 +644,8 @@ static int new_lockspace(const char *name, const char *cluster, current lockspace members are (via configfs) and then tells the lockspace to start running (via sysfs) in dlm_ls_start(). */ - error = do_uevent(ls, 1); - if (error) + error = do_uevent(ls, 1, 0); + if (error < 0) goto out_recoverd; wait_for_completion(&ls->ls_members_done); @@ -665,7 +660,7 @@ static int new_lockspace(const char *name, const char *cluster, return 0; out_members: - do_uevent(ls, 0); + do_uevent(ls, 0, 0); dlm_clear_members(ls); kfree(ls->ls_node_array); out_recoverd: @@ -749,14 +744,14 @@ static int lkb_idr_free(int id, void *p, void *data) This is because there may be LKBs queued as ASTs that have been unlinked from their RSBs and are pending deletion once the AST has been delivered */ -static int lockspace_busy(struct dlm_ls *ls, int force) +static int lockspace_busy(struct dlm_ls *ls, unsigned int release_option) { int rv; spin_lock(&ls->ls_lkbidr_spin); - if (force == 0) { + if (release_option == DLM_RELEASE_NO_LOCKS) { rv = idr_for_each(&ls->ls_lkbidr, lkb_idr_is_any, ls); - } else if (force == 1) { + } else if (release_option == DLM_RELEASE_UNUSED) { rv = idr_for_each(&ls->ls_lkbidr, lkb_idr_is_local, ls); } else { rv = 0; @@ -765,13 +760,13 @@ static int lockspace_busy(struct dlm_ls *ls, int force) return rv; } -static int release_lockspace(struct dlm_ls *ls, int force) +static int release_lockspace(struct dlm_ls *ls, unsigned int release_option) { struct dlm_rsb *rsb; struct rb_node *n; int i, busy, rv; - busy = lockspace_busy(ls, force); + busy = lockspace_busy(ls, release_option); spin_lock(&lslist_lock); if (ls->ls_create_count == 1) { @@ -796,8 +791,9 @@ static int release_lockspace(struct dlm_ls *ls, int force) dlm_device_deregister(ls); - if (force < 3 && dlm_user_daemon_available()) - do_uevent(ls, 0); + if (release_option != DLM_RELEASE_NO_EVENT && + dlm_user_daemon_available()) + do_uevent(ls, 0, (release_option == DLM_RELEASE_RECOVER)); dlm_recoverd_stop(ls); @@ -870,25 +866,24 @@ static int release_lockspace(struct dlm_ls *ls, int force) * lockspace must continue to function as usual, participating in recoveries, * until this returns. * - * Force has 4 possible values: - * 0 - don't destroy locksapce if it has any LKBs - * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs - * 2 - destroy lockspace regardless of LKBs - * 3 - destroy lockspace as part of a forced shutdown + * See DLM_RELEASE defines for release_option values and their meaning. */ -int dlm_release_lockspace(void *lockspace, int force) +int dlm_release_lockspace(void *lockspace, unsigned int release_option) { struct dlm_ls *ls; int error; + if (release_option > __DLM_RELEASE_MAX) + return -EINVAL; + ls = dlm_find_lockspace_local(lockspace); if (!ls) return -EINVAL; dlm_put_lockspace(ls); mutex_lock(&ls_lock); - error = release_lockspace(ls, force); + error = release_lockspace(ls, release_option); if (!error) ls_count--; if (!ls_count) diff --git a/fs/dlm/member.c b/fs/dlm/member.c index 3fda3832cf..a0fdf45fd3 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -454,7 +454,8 @@ static void dlm_lsop_recover_prep(struct dlm_ls *ls) ls->ls_ops->recover_prep(ls->ls_ops_arg); } -static void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb) +static void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb, + unsigned int release_recover) { struct dlm_slot slot; uint32_t seq; @@ -469,9 +470,9 @@ static void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb) we consider the node to have failed (versus being removed due to dlm_release_lockspace) */ - error = dlm_comm_seq(memb->nodeid, &seq); + error = dlm_comm_seq(memb->nodeid, &seq, false); - if (!error && seq == memb->comm_seq) + if (!release_recover && !error && seq == memb->comm_seq) return; slot.nodeid = memb->nodeid; @@ -528,6 +529,7 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) struct dlm_member *memb, *safe; struct dlm_config_node *node; int i, error, neg = 0, low = -1; + unsigned int release_recover; /* previously removed members that we've not finished removing need to count as a negative change so the "neg" recovery steps will happen */ @@ -541,11 +543,21 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) { node = find_config_node(rv, memb->nodeid); - if (node && !node->new) + if (!node) { + log_error(ls, "remove member %d invalid", + memb->nodeid); + return -EFAULT; + } + + if (!node->new && !node->gone) continue; - if (!node) { - log_rinfo(ls, "remove member %d", memb->nodeid); + release_recover = 0; + + if (node->gone) { + release_recover = node->release_recover; + log_rinfo(ls, "remove member %d%s", memb->nodeid, + release_recover ? " (release_recover)" : ""); } else { /* removed and re-added */ log_rinfo(ls, "remove member %d comm_seq %u %u", @@ -555,13 +567,16 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) neg++; list_move(&memb->list, &ls->ls_nodes_gone); ls->ls_num_nodes--; - dlm_lsop_recover_slot(ls, memb); + dlm_lsop_recover_slot(ls, memb, release_recover); } /* add new members to ls_nodes */ for (i = 0; i < rv->nodes_count; i++) { node = &rv->nodes[i]; + if (node->gone) + continue; + if (dlm_is_member(ls, node->nodeid)) continue; dlm_add_member(ls, node); diff --git a/fs/dlm/user.c b/fs/dlm/user.c index defc3beab0..0f4b132be6 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -419,7 +419,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params) dlm_put_lockspace(ls); if (error) - dlm_release_lockspace(lockspace, 0); + dlm_release_lockspace(lockspace, DLM_RELEASE_NO_LOCKS); else error = ls->ls_device.minor; @@ -430,7 +430,7 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) { dlm_lockspace_t *lockspace; struct dlm_ls *ls; - int error, force = 0; + int error, force = DLM_RELEASE_NO_LOCKS; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -440,7 +440,7 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) return -ENOENT; if (params->flags & DLM_USER_LSFLG_FORCEFREE) - force = 2; + force = DLM_RELEASE_NORMAL; lockspace = ls->ls_local_handle; dlm_put_lockspace(ls); diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 3283c12712..65356ce55d 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -640,7 +640,7 @@ static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh) struct gfs2_bufdata *bd; lock_buffer(bh); - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); clear_buffer_dirty(bh); bd = bh->b_private; if (bd) { @@ -656,7 +656,7 @@ static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh) clear_buffer_mapped(bh); clear_buffer_req(bh); clear_buffer_new(bh); - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); unlock_buffer(bh); } @@ -721,7 +721,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) * on dirty buffers like we used to here again. */ - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); head = bh = page_buffers(page); do { if (atomic_read(&bh->b_count)) @@ -753,12 +753,12 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) bh = bh->b_this_page; } while (bh != head); - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); return try_to_free_buffers(page); cannot_release: - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); return 0; } diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 67df5cbd11..b0ab2e9c38 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -67,7 +67,7 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync, struct buffer_head *bh; const unsigned long b_state = (1UL << BH_Dirty)|(1UL << BH_Pinned)|(1UL << BH_Lock); - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); spin_lock(&sdp->sd_ail_lock); list_for_each_entry_safe_reverse(bd, tmp, head, bd_ail_gl_list) { if (nr_revokes == 0) @@ -83,7 +83,7 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync, } GLOCK_BUG_ON(gl, !fsync && atomic_read(&gl->gl_ail_count)); spin_unlock(&sdp->sd_ail_lock); - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); if (gfs2_withdrawing(sdp)) gfs2_withdraw(sdp); @@ -115,10 +115,10 @@ static int gfs2_ail_empty_gl(struct gfs2_glock *gl) * If none of these conditions are true, our revokes are all * flushed and we can return. */ - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); have_revokes = !list_empty(&sdp->sd_log_revokes); log_in_flight = atomic_read(&sdp->sd_log_in_flight); - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); if (have_revokes) goto flush; if (log_in_flight) diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index fabc797f5e..80476629e2 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -1391,7 +1391,7 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table) return 0; fail_release: - dlm_release_lockspace(ls->ls_dlm, 2); + dlm_release_lockspace(ls->ls_dlm, DLM_RELEASE_NORMAL); fail_free: free_recover_size(ls); fail: @@ -1429,7 +1429,7 @@ static void gdlm_unmount(struct gfs2_sbd *sdp) release: down_write(&ls->ls_sem); if (ls->ls_dlm) { - dlm_release_lockspace(ls->ls_dlm, 2); + dlm_release_lockspace(ls->ls_dlm, DLM_RELEASE_NORMAL); ls->ls_dlm = NULL; } up_write(&ls->ls_sem); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 03724f4ef5..8a74ee365b 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -773,9 +773,9 @@ void gfs2_flush_revokes(struct gfs2_sbd *sdp) /* number of revokes we still have room for */ unsigned int max_revokes = atomic_read(&sdp->sd_log_revokes_available); - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); gfs2_ail1_empty(sdp, max_revokes); - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); } /** @@ -1055,7 +1055,7 @@ repeat: goto out_withdraw; lops_after_commit(sdp, tr); - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); sdp->sd_log_blks_reserved = 0; spin_lock(&sdp->sd_ail_lock); @@ -1064,7 +1064,7 @@ repeat: tr = NULL; } spin_unlock(&sdp->sd_ail_lock); - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); if (!(flags & GFS2_LOG_HEAD_FLUSH_NORMAL)) { if (!sdp->sd_log_idle) { @@ -1152,7 +1152,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) unsigned int unused; unsigned int maxres; - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); if (sdp->sd_log_tr) { gfs2_merge_trans(sdp, tr); @@ -1170,7 +1170,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) gfs2_log_release(sdp, unused); sdp->sd_log_blks_reserved = reserved; - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); } /** diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index c18c9358a3..bc94445040 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -23,30 +23,6 @@ */ #define GFS2_LOG_FLUSH_MIN_BLOCKS 4 -/** - * gfs2_log_lock - acquire the right to mess with the log manager - * @sdp: the filesystem - * - */ - -static inline void gfs2_log_lock(struct gfs2_sbd *sdp) -__acquires(&sdp->sd_log_lock) -{ - spin_lock(&sdp->sd_log_lock); -} - -/** - * gfs2_log_unlock - release the right to mess with the log manager - * @sdp: the filesystem - * - */ - -static inline void gfs2_log_unlock(struct gfs2_sbd *sdp) -__releases(&sdp->sd_log_lock) -{ - spin_unlock(&sdp->sd_log_lock); -} - static inline void gfs2_ordered_add_inode(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index cd59140dbe..ae7da65109 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -659,19 +659,19 @@ static void gfs2_before_commit(struct gfs2_sbd *sdp, unsigned int limit, unsigned n; __be64 *ptr; - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); list_sort(NULL, blist, blocknr_cmp); bd1 = bd2 = list_prepare_entry(bd1, blist, bd_list); while(total) { num = total; if (total > limit) num = limit; - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); page = gfs2_get_log_desc(sdp, is_databuf ? GFS2_LOG_DESC_JDATA : GFS2_LOG_DESC_METADATA, num + 1, num); ld = page_address(page); - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); ptr = (__be64 *)(ld + 1); n = 0; @@ -685,14 +685,14 @@ static void gfs2_before_commit(struct gfs2_sbd *sdp, unsigned int limit, break; } - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); gfs2_log_write_page(sdp, page); - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); n = 0; list_for_each_entry_continue(bd2, blist, bd_list) { get_bh(bd2->bd_bh); - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); lock_buffer(bd2->bd_bh); if (buffer_escaped(bd2->bd_bh)) { @@ -711,7 +711,7 @@ static void gfs2_before_commit(struct gfs2_sbd *sdp, unsigned int limit, } else { gfs2_log_write_bh(sdp, bd2->bd_bh); } - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); if (++n >= num) break; } @@ -719,7 +719,7 @@ static void gfs2_before_commit(struct gfs2_sbd *sdp, unsigned int limit, BUG_ON(total < num); total -= num; } - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); } static void buf_lo_before_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 6ca7376b18..83b6f0e454 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -386,7 +386,7 @@ static void gfs2_ail1_wipe(struct gfs2_sbd *sdp, u64 bstart, u32 blen) struct buffer_head *bh; u64 end = bstart + blen; - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); spin_lock(&sdp->sd_ail_lock); list_for_each_entry_safe(tr, s, &sdp->sd_ail1_list, tr_list) { list_for_each_entry_safe(bd, bs, &tr->tr_ail1_list, @@ -399,7 +399,7 @@ static void gfs2_ail1_wipe(struct gfs2_sbd *sdp, u64 bstart, u32 blen) } } spin_unlock(&sdp->sd_ail_lock); - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); } static struct buffer_head *gfs2_getjdatabuf(struct gfs2_inode *ip, u64 blkno) @@ -459,11 +459,11 @@ void gfs2_journal_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen) } if (bh) { lock_buffer(bh); - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); spin_lock(&sdp->sd_ail_lock); gfs2_remove_from_journal(bh, ty); spin_unlock(&sdp->sd_ail_lock); - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); unlock_buffer(bh); brelse(bh); } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 07d912f3f9..ccbdda807d 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1374,6 +1374,35 @@ out: return ret; } +static int gfs2_truncate_inode_pages(struct inode *inode) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + struct address_space *mapping = &inode->i_data; + bool need_trans = gfs2_is_jdata(ip) && mapping->nrpages; + int ret; + + /* + * Truncating a jdata inode address space may create revokes in + * truncate_inode_pages() -> gfs2_invalidate_folio() -> ... -> + * gfs2_remove_from_journal(), so we need a transaction here. + * + * FIXME: During a withdraw, no new transactions can be created. + * In that case, we skip the truncate, but that doesn't help because + * truncate_inode_pages_final() will then call gfs2_invalidate_folio() + * again, and outside of a transaction. + */ + if (need_trans) { + ret = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); + if (ret) + return ret; + } + truncate_inode_pages(mapping, 0); + if (need_trans) + gfs2_trans_end(sdp); + return 0; +} + /* * evict_linked_inode - evict an inode whose dinode has not been unlinked * @inode: The inode to evict @@ -1409,7 +1438,9 @@ static int evict_linked_inode(struct inode *inode, struct gfs2_holder *gh) gfs2_ail_flush(gl, 0); clean: - truncate_inode_pages(&inode->i_data, 0); + ret = gfs2_truncate_inode_pages(inode); + if (ret) + return ret; truncate_inode_pages(metamapping, 0); return 0; } diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 84b9f77618..821d46c7ea 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -174,7 +174,6 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl, INIT_LIST_HEAD(&bd->bd_list); INIT_LIST_HEAD(&bd->bd_ail_st_list); INIT_LIST_HEAD(&bd->bd_ail_gl_list); - bh->b_private = bd; return bd; } @@ -203,17 +202,20 @@ void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh) set_bit(TR_TOUCHED, &tr->tr_flags); goto out; } - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); bd = bh->b_private; if (bd == NULL) { - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); unlock_buffer(bh); - if (bh->b_private == NULL) - bd = gfs2_alloc_bufdata(gl, bh); - else - bd = bh->b_private; + bd = gfs2_alloc_bufdata(gl, bh); lock_buffer(bh); - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); + if (bh->b_private) { + kmem_cache_free(gfs2_bufdata_cachep, bd); + bd = bh->b_private; + } else { + bh->b_private = bd; + } } gfs2_assert(sdp, bd->bd_gl == gl); set_bit(TR_TOUCHED, &tr->tr_flags); @@ -224,7 +226,7 @@ void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh) tr->tr_num_databuf_new++; list_add_tail(&bd->bd_list, &tr->tr_databuf); } - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); out: unlock_buffer(bh); } @@ -244,19 +246,20 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh) set_bit(TR_TOUCHED, &tr->tr_flags); goto out; } - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); bd = bh->b_private; if (bd == NULL) { - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); unlock_buffer(bh); - lock_page(bh->b_page); - if (bh->b_private == NULL) - bd = gfs2_alloc_bufdata(gl, bh); - else - bd = bh->b_private; - unlock_page(bh->b_page); + bd = gfs2_alloc_bufdata(gl, bh); lock_buffer(bh); - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); + if (bh->b_private) { + kmem_cache_free(gfs2_bufdata_cachep, bd); + bd = bh->b_private; + } else { + bh->b_private = bd; + } } gfs2_assert(sdp, bd->bd_gl == gl); set_bit(TR_TOUCHED, &tr->tr_flags); @@ -287,7 +290,7 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh) list_add(&bd->bd_list, &tr->tr_buf); tr->tr_num_buf_new++; out_unlock: - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); if (withdraw) gfs2_assert_withdraw(sdp, 0); out: @@ -309,7 +312,7 @@ void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len) struct gfs2_bufdata *bd, *tmp; unsigned int n = len; - gfs2_log_lock(sdp); + spin_lock(&sdp->sd_log_lock); list_for_each_entry_safe(bd, tmp, &sdp->sd_log_revokes, bd_list) { if ((bd->bd_blkno >= blkno) && (bd->bd_blkno < (blkno + len))) { list_del_init(&bd->bd_list); @@ -323,7 +326,7 @@ void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len) break; } } - gfs2_log_unlock(sdp); + spin_unlock(&sdp->sd_log_lock); } void gfs2_trans_free(struct gfs2_sbd *sdp, struct gfs2_trans *tr) diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index d2fb97b173..5ece21419f 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c @@ -981,7 +981,7 @@ static const struct dlm_lockspace_ops ocfs2_ls_ops = { static int user_cluster_disconnect(struct ocfs2_cluster_connection *conn) { version_unlock(conn); - dlm_release_lockspace(conn->cc_lockspace, 2); + dlm_release_lockspace(conn->cc_lockspace, DLM_RELEASE_NORMAL); conn->cc_lockspace = NULL; ocfs2_live_connection_drop(conn->cc_private); conn->cc_private = NULL; diff --git a/include/linux/dlm.h b/include/linux/dlm.h index d02da2c6fc..da3c6eaf4b 100644 --- a/include/linux/dlm.h +++ b/include/linux/dlm.h @@ -87,13 +87,44 @@ int dlm_new_lockspace(const char *name, const char *cluster, const struct dlm_lockspace_ops *ops, void *ops_arg, int *ops_result, dlm_lockspace_t **lockspace); +/* + * dlm_release_lockspace() release_option values: + * + * DLM_RELEASE_NO_LOCKS returns -EBUSY if any locks (lkb's) + * exist in the local lockspace. + * + * DLM_RELEASE_UNUSED previous value that is no longer used. + * + * DLM_RELEASE_NORMAL releases the lockspace regardless of any + * locks managed in the local lockspace. + * + * DLM_RELEASE_NO_EVENT release the lockspace regardless of any + * locks managed in the local lockspace, and does not submit + * a leave event to the cluster manager, so other nodes will + * not be notified that the node should be removed from the + * list of lockspace members. + * + * DLM_RELEASE_RECOVER like DLM_RELEASE_NORMAL, but the remaining + * nodes will handle the removal of the node as if the node + * had failed, e.g. the recover_slot() callback would be used. + */ +#define DLM_RELEASE_NO_LOCKS 0 +#define DLM_RELEASE_UNUSED 1 +#define DLM_RELEASE_NORMAL 2 +#define DLM_RELEASE_NO_EVENT 3 +#define DLM_RELEASE_RECOVER 4 +#define __DLM_RELEASE_MAX DLM_RELEASE_RECOVER + /* * dlm_release_lockspace * * Stop a lockspace. + * + * release_option: see DLM_RELEASE values above. */ -int dlm_release_lockspace(dlm_lockspace_t *lockspace, int force); +int dlm_release_lockspace(dlm_lockspace_t *lockspace, + unsigned int release_option); /* * dlm_lock diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index e87dc67f33..e2eac8db2a 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -322,60 +322,90 @@ static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm) return 0; } +static bool is_access_interleaved(snd_pcm_access_t access) +{ + switch (access) { + case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED: + case SNDRV_PCM_ACCESS_RW_INTERLEAVED: + return true; + default: + return false; + } +}; + static int loopback_check_format(struct loopback_cable *cable, int stream) { + struct loopback_pcm *dpcm_play, *dpcm_capt; struct snd_pcm_runtime *runtime, *cruntime; struct loopback_setup *setup; struct snd_card *card; - int check; + bool stop_capture = false; + unsigned long flags; + int ret = 0, check; + + spin_lock_irqsave(&cable->lock, flags); + dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; + dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; if (cable->valid != CABLE_VALID_BOTH) { - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - goto __notify; - return 0; - } - runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> - substream->runtime; - cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> - substream->runtime; - check = runtime->format != cruntime->format || + if (stream == SNDRV_PCM_STREAM_CAPTURE || !dpcm_play) + goto unlock; + } else { + if (!dpcm_play || !dpcm_capt) + goto unlock_eio; + runtime = dpcm_play->substream->runtime; + cruntime = dpcm_capt->substream->runtime; + if (!runtime || !cruntime) + goto unlock_eio; + check = runtime->format != cruntime->format || runtime->rate != cruntime->rate || runtime->channels != cruntime->channels || - runtime->access != cruntime->access; - if (!check) - return 0; - if (stream == SNDRV_PCM_STREAM_CAPTURE) { - return -EIO; - } else { - snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> - substream, SNDRV_PCM_STATE_DRAINING); - __notify: - runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> - substream->runtime; - setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); - card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; - if (setup->format != runtime->format) { - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, - &setup->format_id); - setup->format = runtime->format; - } - if (setup->rate != runtime->rate) { - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, - &setup->rate_id); - setup->rate = runtime->rate; - } - if (setup->channels != runtime->channels) { - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, - &setup->channels_id); - setup->channels = runtime->channels; - } - if (setup->access != runtime->access) { - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, - &setup->access_id); - setup->access = runtime->access; - } + is_access_interleaved(runtime->access) != + is_access_interleaved(cruntime->access); + if (!check) + goto unlock; + if (stream == SNDRV_PCM_STREAM_CAPTURE) + goto unlock_eio; + else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) + stop_capture = true; } + + setup = get_setup(dpcm_play); + card = dpcm_play->loopback->card; + runtime = dpcm_play->substream->runtime; + if (setup->format != runtime->format) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->format_id); + setup->format = runtime->format; + } + if (setup->rate != runtime->rate) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->rate_id); + setup->rate = runtime->rate; + } + if (setup->channels != runtime->channels) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->channels_id); + setup->channels = runtime->channels; + } + if (is_access_interleaved(setup->access) != + is_access_interleaved(runtime->access)) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->access_id); + setup->access = runtime->access; + } + spin_unlock_irqrestore(&cable->lock, flags); + + if (stop_capture) + snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING); + return 0; + +unlock_eio: + ret = -EIO; +unlock: + spin_unlock_irqrestore(&cable->lock, flags); + return ret; } static void loopback_active_notify(struct loopback_pcm *dpcm) @@ -584,8 +614,7 @@ static void copy_play_buf(struct loopback_pcm *play, size = play->pcm_buffer_size - src_off; if (dst_off + size > capt->pcm_buffer_size) size = capt->pcm_buffer_size - dst_off; - if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED || - runtime->access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) + if (!is_access_interleaved(runtime->access)) copy_play_buf_part_n(play, capt, size, src_off, dst_off); else memcpy(dst + dst_off, src + src_off, size); @@ -1544,8 +1573,7 @@ static int loopback_access_get(struct snd_kcontrol *kcontrol, mutex_lock(&loopback->cable_lock); access = loopback->setup[kcontrol->id.subdevice][kcontrol->id.device].access; - ucontrol->value.enumerated.item[0] = access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED || - access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED; + ucontrol->value.enumerated.item[0] = !is_access_interleaved(access); mutex_unlock(&loopback->cable_lock); return 0;