Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions arch/x86/hyperv/hv_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ static int hv_cpu_init(unsigned int cpu)
struct page *pg;

input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
pg = alloc_page(GFP_KERNEL);
/* hv_cpu_init() can be called with IRQs disabled from hv_resume() */
pg = alloc_page(irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
if (unlikely(!pg))
return -ENOMEM;
*input_arg = page_address(pg);
Expand Down Expand Up @@ -254,6 +255,7 @@ static int __init hv_pci_init(void)
static int hv_suspend(void)
{
union hv_x64_msr_hypercall_contents hypercall_msr;
int ret;

/*
* Reset the hypercall page as it is going to be invalidated
Expand All @@ -270,12 +272,17 @@ static int hv_suspend(void)
hypercall_msr.enable = 0;
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);

return 0;
ret = hv_cpu_die(0);
return ret;
}

static void hv_resume(void)
{
union hv_x64_msr_hypercall_contents hypercall_msr;
int ret;

ret = hv_cpu_init(0);
WARN_ON(ret);

/* Re-enable the hypercall page */
rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
Expand All @@ -288,6 +295,7 @@ static void hv_resume(void)
hv_hypercall_pg_saved = NULL;
}

/* Note: when the ops are called, only CPU0 is online and IRQs are disabled. */
static struct syscore_ops hv_syscore_ops = {
.suspend = hv_suspend,
.resume = hv_resume,
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/mshyperv.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ typedef int (*hyperv_fill_flush_list_func)(
rdmsrl(HV_X64_MSR_SINT0 + int_num, val)
#define hv_set_synint_state(int_num, val) \
wrmsrl(HV_X64_MSR_SINT0 + int_num, val)
#define hv_recommend_using_aeoi() \
(!(ms_hyperv.hints & HV_DEPRECATING_AEOI_RECOMMENDED))

#define hv_get_crash_ctl(val) \
rdmsrl(HV_X64_MSR_CRASH_CTL, val)
Expand Down
6 changes: 1 addition & 5 deletions drivers/hv/hv.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,7 @@ void hv_synic_enable_regs(unsigned int cpu)

shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR;
shared_sint.masked = false;
if (ms_hyperv.hints & HV_DEPRECATING_AEOI_RECOMMENDED)
shared_sint.auto_eoi = false;
else
shared_sint.auto_eoi = true;

shared_sint.auto_eoi = hv_recommend_using_aeoi();
hv_set_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64);

/* Enable the global synic bit */
Expand Down
4 changes: 2 additions & 2 deletions drivers/hv/hv_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ TRACE_EVENT(vmbus_send_tl_connect_request,
__field(int, ret)
),
TP_fast_assign(
memcpy(__entry->guest_id, &msg->guest_endpoint_id.b, 16);
memcpy(__entry->host_id, &msg->host_service_id.b, 16);
export_guid(__entry->guest_id, &msg->guest_endpoint_id);
export_guid(__entry->host_id, &msg->host_service_id);
__entry->ret = ret;
),
TP_printk("sending guest_endpoint_id %pUl, host_service_id %pUl, "
Expand Down
43 changes: 34 additions & 9 deletions drivers/hv/vmbus_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,9 @@ static int vmbus_resume(struct device *child_device)

return drv->resume(dev);
}
#else
#define vmbus_suspend NULL
#define vmbus_resume NULL
#endif /* CONFIG_PM_SLEEP */

/*
Expand All @@ -997,11 +1000,22 @@ static void vmbus_device_release(struct device *device)
}

/*
* Note: we must use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS rather than
* SET_SYSTEM_SLEEP_PM_OPS: see the comment before vmbus_bus_pm.
* Note: we must use the "noirq" ops: see the comment before vmbus_bus_pm.
*
* suspend_noirq/resume_noirq are set to NULL to support Suspend-to-Idle: we
* shouldn't suspend the vmbus devices upon Suspend-to-Idle, otherwise there
* is no way to wake up a Generation-2 VM.
*
* The other 4 ops are for hibernation.
*/

static const struct dev_pm_ops vmbus_pm = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(vmbus_suspend, vmbus_resume)
.suspend_noirq = NULL,
.resume_noirq = NULL,
.freeze_noirq = vmbus_suspend,
.thaw_noirq = vmbus_resume,
.poweroff_noirq = vmbus_suspend,
.restore_noirq = vmbus_resume,
};

/* The one and only one */
Expand Down Expand Up @@ -2281,6 +2295,9 @@ static int vmbus_bus_resume(struct device *dev)

return 0;
}
#else
#define vmbus_bus_suspend NULL
#define vmbus_bus_resume NULL
#endif /* CONFIG_PM_SLEEP */

static const struct acpi_device_id vmbus_acpi_device_ids[] = {
Expand All @@ -2291,16 +2308,24 @@ static const struct acpi_device_id vmbus_acpi_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, vmbus_acpi_device_ids);

/*
* Note: we must use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS rather than
* SET_SYSTEM_SLEEP_PM_OPS, otherwise NIC SR-IOV can not work, because the
* "pci_dev_pm_ops" uses the "noirq" callbacks: in the resume path, the
* pci "noirq" restore callback runs before "non-noirq" callbacks (see
* Note: we must use the "no_irq" ops, otherwise hibernation can not work with
* PCI device assignment, because "pci_dev_pm_ops" uses the "noirq" ops: in
* the resume path, the pci "noirq" restore op runs before "non-noirq" op (see
* resume_target_kernel() -> dpm_resume_start(), and hibernation_restore() ->
* dpm_resume_end()). This means vmbus_bus_resume() and the pci-hyperv's
* resume callback must also run via the "noirq" callbacks.
* resume callback must also run via the "noirq" ops.
*
* Set suspend_noirq/resume_noirq to NULL for Suspend-to-Idle: see the comment
* earlier in this file before vmbus_pm.
*/

static const struct dev_pm_ops vmbus_bus_pm = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(vmbus_bus_suspend, vmbus_bus_resume)
.suspend_noirq = NULL,
.resume_noirq = NULL,
.freeze_noirq = vmbus_bus_suspend,
.thaw_noirq = vmbus_bus_resume,
.poweroff_noirq = vmbus_bus_suspend,
.restore_noirq = vmbus_bus_resume
};

static struct acpi_driver vmbus_acpi_driver = {
Expand Down
20 changes: 14 additions & 6 deletions fs/btrfs/block-group.c
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
path = btrfs_alloc_path();
if (!path) {
ret = -ENOMEM;
goto out;
goto out_put_group;
}

/*
Expand Down Expand Up @@ -954,7 +954,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
ret = btrfs_orphan_add(trans, BTRFS_I(inode));
if (ret) {
btrfs_add_delayed_iput(inode);
goto out;
goto out_put_group;
}
clear_nlink(inode);
/* One for the block groups ref */
Expand All @@ -977,13 +977,13 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,

ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
if (ret < 0)
goto out;
goto out_put_group;
if (ret > 0)
btrfs_release_path(path);
if (ret == 0) {
ret = btrfs_del_item(trans, tree_root, path);
if (ret)
goto out;
goto out_put_group;
btrfs_release_path(path);
}

Expand Down Expand Up @@ -1102,9 +1102,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,

ret = remove_block_group_free_space(trans, block_group);
if (ret)
goto out;
goto out_put_group;

btrfs_put_block_group(block_group);
/* Once for the block groups rbtree */
btrfs_put_block_group(block_group);

ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
Expand All @@ -1127,6 +1127,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
/* once for the tree */
free_extent_map(em);
}

out_put_group:
/* Once for the lookup reference */
btrfs_put_block_group(block_group);
out:
if (remove_rsv)
btrfs_delayed_refs_rsv_release(fs_info, 1);
Expand Down Expand Up @@ -1288,11 +1292,15 @@ static bool clean_pinned_extents(struct btrfs_trans_handle *trans,
if (ret)
goto err;
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
if (prev_trans)
btrfs_put_transaction(prev_trans);

return true;

err:
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
if (prev_trans)
btrfs_put_transaction(prev_trans);
btrfs_dec_block_group_ro(bg);
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/discard.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef BTRFS_DISCARD_H
#define BTRFS_DISCARD_H
Expand Down
36 changes: 32 additions & 4 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -2036,9 +2036,6 @@ void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info)
for (i = 0; i < ret; i++)
btrfs_drop_and_free_fs_root(fs_info, gang[i]);
}

if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
btrfs_free_log_root_tree(NULL, fs_info);
}

static void btrfs_init_scrub(struct btrfs_fs_info *fs_info)
Expand Down Expand Up @@ -3888,7 +3885,7 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
spin_unlock(&fs_info->fs_roots_radix_lock);

if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
btrfs_free_log(NULL, root);
ASSERT(root->log_root == NULL);
if (root->reloc_root) {
btrfs_put_root(root->reloc_root);
root->reloc_root = NULL;
Expand Down Expand Up @@ -4211,6 +4208,36 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
up_write(&fs_info->cleanup_work_sem);
}

static void btrfs_drop_all_logs(struct btrfs_fs_info *fs_info)
{
struct btrfs_root *gang[8];
u64 root_objectid = 0;
int ret;

spin_lock(&fs_info->fs_roots_radix_lock);
while ((ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
(void **)gang, root_objectid,
ARRAY_SIZE(gang))) != 0) {
int i;

for (i = 0; i < ret; i++)
gang[i] = btrfs_grab_root(gang[i]);
spin_unlock(&fs_info->fs_roots_radix_lock);

for (i = 0; i < ret; i++) {
if (!gang[i])
continue;
root_objectid = gang[i]->root_key.objectid;
btrfs_free_log(NULL, gang[i]);
btrfs_put_root(gang[i]);
}
root_objectid++;
spin_lock(&fs_info->fs_roots_radix_lock);
}
spin_unlock(&fs_info->fs_roots_radix_lock);
btrfs_free_log_root_tree(NULL, fs_info);
}

static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
{
struct btrfs_ordered_extent *ordered;
Expand Down Expand Up @@ -4603,6 +4630,7 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info)
btrfs_destroy_delayed_inodes(fs_info);
btrfs_assert_delayed_root_empty(fs_info);
btrfs_destroy_all_delalloc_inodes(fs_info);
btrfs_drop_all_logs(fs_info);
mutex_unlock(&fs_info->transaction_kthread_mutex);

return 0;
Expand Down
1 change: 1 addition & 0 deletions fs/btrfs/relocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -4559,6 +4559,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
if (IS_ERR(fs_root)) {
err = PTR_ERR(fs_root);
list_add_tail(&reloc_root->root_list, &reloc_roots);
btrfs_end_transaction(trans);
goto out_unset;
}

Expand Down
4 changes: 2 additions & 2 deletions include/uapi/linux/hyperv.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ enum hv_fcopy_op {

struct hv_fcopy_hdr {
__u32 operation;
uuid_le service_id0; /* currently unused */
uuid_le service_id1; /* currently unused */
__u8 service_id0[16]; /* currently unused */
__u8 service_id1[16]; /* currently unused */
} __attribute__((packed));

#define OVER_WRITE 0x1
Expand Down