mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge 4.11-rc4 into char-misc-next
We want the char-misc fixes in here as well. Signed-off-by: Greg Kroah-Hartman <[email protected]>
This commit is contained in:
commit
57c0eabbd5
727 changed files with 9277 additions and 5625 deletions
|
|
@ -502,12 +502,15 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
|
|||
|
||||
wait_for_completion(&info->waitevent);
|
||||
|
||||
if (channel->rescind) {
|
||||
ret = -ENODEV;
|
||||
goto post_msg_err;
|
||||
}
|
||||
|
||||
post_msg_err:
|
||||
/*
|
||||
* If the channel has been rescinded;
|
||||
* we will be awakened by the rescind
|
||||
* handler; set the error code to zero so we don't leak memory.
|
||||
*/
|
||||
if (channel->rescind)
|
||||
ret = 0;
|
||||
|
||||
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
|
||||
list_del(&info->msglistentry);
|
||||
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
|
||||
|
|
@ -530,15 +533,13 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
|
|||
int ret;
|
||||
|
||||
/*
|
||||
* vmbus_on_event(), running in the tasklet, can race
|
||||
* vmbus_on_event(), running in the per-channel tasklet, can race
|
||||
* with vmbus_close_internal() in the case of SMP guest, e.g., when
|
||||
* the former is accessing channel->inbound.ring_buffer, the latter
|
||||
* could be freeing the ring_buffer pages.
|
||||
*
|
||||
* To resolve the race, we can serialize them by disabling the
|
||||
* tasklet when the latter is running here.
|
||||
* could be freeing the ring_buffer pages, so here we must stop it
|
||||
* first.
|
||||
*/
|
||||
hv_event_tasklet_disable(channel);
|
||||
tasklet_disable(&channel->callback_event);
|
||||
|
||||
/*
|
||||
* In case a device driver's probe() fails (e.g.,
|
||||
|
|
@ -605,8 +606,6 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
|
|||
get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
|
||||
|
||||
out:
|
||||
hv_event_tasklet_enable(channel);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -350,7 +350,8 @@ static struct vmbus_channel *alloc_channel(void)
|
|||
static void free_channel(struct vmbus_channel *channel)
|
||||
{
|
||||
tasklet_kill(&channel->callback_event);
|
||||
kfree(channel);
|
||||
|
||||
kfree_rcu(channel, rcu);
|
||||
}
|
||||
|
||||
static void percpu_channel_enq(void *arg)
|
||||
|
|
@ -359,14 +360,14 @@ static void percpu_channel_enq(void *arg)
|
|||
struct hv_per_cpu_context *hv_cpu
|
||||
= this_cpu_ptr(hv_context.cpu_context);
|
||||
|
||||
list_add_tail(&channel->percpu_list, &hv_cpu->chan_list);
|
||||
list_add_tail_rcu(&channel->percpu_list, &hv_cpu->chan_list);
|
||||
}
|
||||
|
||||
static void percpu_channel_deq(void *arg)
|
||||
{
|
||||
struct vmbus_channel *channel = arg;
|
||||
|
||||
list_del(&channel->percpu_list);
|
||||
list_del_rcu(&channel->percpu_list);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -381,19 +382,6 @@ static void vmbus_release_relid(u32 relid)
|
|||
true);
|
||||
}
|
||||
|
||||
void hv_event_tasklet_disable(struct vmbus_channel *channel)
|
||||
{
|
||||
tasklet_disable(&channel->callback_event);
|
||||
}
|
||||
|
||||
void hv_event_tasklet_enable(struct vmbus_channel *channel)
|
||||
{
|
||||
tasklet_enable(&channel->callback_event);
|
||||
|
||||
/* In case there is any pending event */
|
||||
tasklet_schedule(&channel->callback_event);
|
||||
}
|
||||
|
||||
void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
|
@ -402,7 +390,6 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
|
|||
BUG_ON(!channel->rescind);
|
||||
BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
|
||||
|
||||
hv_event_tasklet_disable(channel);
|
||||
if (channel->target_cpu != get_cpu()) {
|
||||
put_cpu();
|
||||
smp_call_function_single(channel->target_cpu,
|
||||
|
|
@ -411,7 +398,6 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
|
|||
percpu_channel_deq(channel);
|
||||
put_cpu();
|
||||
}
|
||||
hv_event_tasklet_enable(channel);
|
||||
|
||||
if (channel->primary_channel == NULL) {
|
||||
list_del(&channel->listentry);
|
||||
|
|
@ -505,7 +491,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
|
|||
|
||||
init_vp_index(newchannel, dev_type);
|
||||
|
||||
hv_event_tasklet_disable(newchannel);
|
||||
if (newchannel->target_cpu != get_cpu()) {
|
||||
put_cpu();
|
||||
smp_call_function_single(newchannel->target_cpu,
|
||||
|
|
@ -515,7 +500,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
|
|||
percpu_channel_enq(newchannel);
|
||||
put_cpu();
|
||||
}
|
||||
hv_event_tasklet_enable(newchannel);
|
||||
|
||||
/*
|
||||
* This state is used to indicate a successful open
|
||||
|
|
@ -565,7 +549,6 @@ err_deq_chan:
|
|||
list_del(&newchannel->listentry);
|
||||
mutex_unlock(&vmbus_connection.channel_mutex);
|
||||
|
||||
hv_event_tasklet_disable(newchannel);
|
||||
if (newchannel->target_cpu != get_cpu()) {
|
||||
put_cpu();
|
||||
smp_call_function_single(newchannel->target_cpu,
|
||||
|
|
@ -574,7 +557,6 @@ err_deq_chan:
|
|||
percpu_channel_deq(newchannel);
|
||||
put_cpu();
|
||||
}
|
||||
hv_event_tasklet_enable(newchannel);
|
||||
|
||||
vmbus_release_relid(newchannel->offermsg.child_relid);
|
||||
|
||||
|
|
@ -814,6 +796,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
|
|||
/* Allocate the channel object and save this offer. */
|
||||
newchannel = alloc_channel();
|
||||
if (!newchannel) {
|
||||
vmbus_release_relid(offer->child_relid);
|
||||
pr_err("Unable to allocate channel object\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
|
|||
static const char fcopy_devname[] = "vmbus/hv_fcopy";
|
||||
static u8 *recv_buffer;
|
||||
static struct hvutil_transport *hvt;
|
||||
static struct completion release_event;
|
||||
/*
|
||||
* This state maintains the version number registered by the daemon.
|
||||
*/
|
||||
|
|
@ -329,7 +328,6 @@ static void fcopy_on_reset(void)
|
|||
|
||||
if (cancel_delayed_work_sync(&fcopy_timeout_work))
|
||||
fcopy_respond_to_host(HV_E_FAIL);
|
||||
complete(&release_event);
|
||||
}
|
||||
|
||||
int hv_fcopy_init(struct hv_util_service *srv)
|
||||
|
|
@ -337,7 +335,6 @@ int hv_fcopy_init(struct hv_util_service *srv)
|
|||
recv_buffer = srv->recv_buffer;
|
||||
fcopy_transaction.recv_channel = srv->channel;
|
||||
|
||||
init_completion(&release_event);
|
||||
/*
|
||||
* When this driver loads, the user level daemon that
|
||||
* processes the host requests may not yet be running.
|
||||
|
|
@ -359,5 +356,4 @@ void hv_fcopy_deinit(void)
|
|||
fcopy_transaction.state = HVUTIL_DEVICE_DYING;
|
||||
cancel_delayed_work_sync(&fcopy_timeout_work);
|
||||
hvutil_transport_destroy(hvt);
|
||||
wait_for_completion(&release_event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
|
|||
static const char kvp_devname[] = "vmbus/hv_kvp";
|
||||
static u8 *recv_buffer;
|
||||
static struct hvutil_transport *hvt;
|
||||
static struct completion release_event;
|
||||
/*
|
||||
* Register the kernel component with the user-level daemon.
|
||||
* As part of this registration, pass the LIC version number.
|
||||
|
|
@ -712,7 +711,6 @@ static void kvp_on_reset(void)
|
|||
if (cancel_delayed_work_sync(&kvp_timeout_work))
|
||||
kvp_respond_to_host(NULL, HV_E_FAIL);
|
||||
kvp_transaction.state = HVUTIL_DEVICE_INIT;
|
||||
complete(&release_event);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -721,7 +719,6 @@ hv_kvp_init(struct hv_util_service *srv)
|
|||
recv_buffer = srv->recv_buffer;
|
||||
kvp_transaction.recv_channel = srv->channel;
|
||||
|
||||
init_completion(&release_event);
|
||||
/*
|
||||
* When this driver loads, the user level daemon that
|
||||
* processes the host requests may not yet be running.
|
||||
|
|
@ -745,5 +742,4 @@ void hv_kvp_deinit(void)
|
|||
cancel_delayed_work_sync(&kvp_timeout_work);
|
||||
cancel_work_sync(&kvp_sendkey_work);
|
||||
hvutil_transport_destroy(hvt);
|
||||
wait_for_completion(&release_event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ static int dm_reg_value;
|
|||
static const char vss_devname[] = "vmbus/hv_vss";
|
||||
static __u8 *recv_buffer;
|
||||
static struct hvutil_transport *hvt;
|
||||
static struct completion release_event;
|
||||
|
||||
static void vss_timeout_func(struct work_struct *dummy);
|
||||
static void vss_handle_request(struct work_struct *dummy);
|
||||
|
|
@ -359,13 +358,11 @@ static void vss_on_reset(void)
|
|||
if (cancel_delayed_work_sync(&vss_timeout_work))
|
||||
vss_respond_to_host(HV_E_FAIL);
|
||||
vss_transaction.state = HVUTIL_DEVICE_INIT;
|
||||
complete(&release_event);
|
||||
}
|
||||
|
||||
int
|
||||
hv_vss_init(struct hv_util_service *srv)
|
||||
{
|
||||
init_completion(&release_event);
|
||||
if (vmbus_proto_version < VERSION_WIN8_1) {
|
||||
pr_warn("Integration service 'Backup (volume snapshot)'"
|
||||
" not supported on this host version.\n");
|
||||
|
|
@ -398,5 +395,4 @@ void hv_vss_deinit(void)
|
|||
cancel_delayed_work_sync(&vss_timeout_work);
|
||||
cancel_work_sync(&vss_handle_request_work);
|
||||
hvutil_transport_destroy(hvt);
|
||||
wait_for_completion(&release_event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -590,6 +590,8 @@ static int hv_timesync_init(struct hv_util_service *srv)
|
|||
if (!hyperv_cs)
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_init(&host_ts.lock);
|
||||
|
||||
INIT_WORK(&wrk.work, hv_set_host_time);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -182,10 +182,11 @@ static int hvt_op_release(struct inode *inode, struct file *file)
|
|||
* connects back.
|
||||
*/
|
||||
hvt_reset(hvt);
|
||||
mutex_unlock(&hvt->lock);
|
||||
|
||||
if (mode_old == HVUTIL_TRANSPORT_DESTROY)
|
||||
hvt_transport_free(hvt);
|
||||
complete(&hvt->release);
|
||||
|
||||
mutex_unlock(&hvt->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -304,6 +305,7 @@ struct hvutil_transport *hvutil_transport_init(const char *name,
|
|||
|
||||
init_waitqueue_head(&hvt->outmsg_q);
|
||||
mutex_init(&hvt->lock);
|
||||
init_completion(&hvt->release);
|
||||
|
||||
spin_lock(&hvt_list_lock);
|
||||
list_add(&hvt->list, &hvt_list);
|
||||
|
|
@ -351,6 +353,8 @@ void hvutil_transport_destroy(struct hvutil_transport *hvt)
|
|||
if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0)
|
||||
cn_del_callback(&hvt->cn_id);
|
||||
|
||||
if (mode_old != HVUTIL_TRANSPORT_CHARDEV)
|
||||
hvt_transport_free(hvt);
|
||||
if (mode_old == HVUTIL_TRANSPORT_CHARDEV)
|
||||
wait_for_completion(&hvt->release);
|
||||
|
||||
hvt_transport_free(hvt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ struct hvutil_transport {
|
|||
int outmsg_len; /* its length */
|
||||
wait_queue_head_t outmsg_q; /* poll/read wait queue */
|
||||
struct mutex lock; /* protects struct members */
|
||||
struct completion release; /* synchronize with fd release */
|
||||
};
|
||||
|
||||
struct hvutil_transport *hvutil_transport_init(const char *name,
|
||||
|
|
|
|||
|
|
@ -937,8 +937,10 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu)
|
|||
if (relid == 0)
|
||||
continue;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Find channel based on relid */
|
||||
list_for_each_entry(channel, &hv_cpu->chan_list, percpu_list) {
|
||||
list_for_each_entry_rcu(channel, &hv_cpu->chan_list, percpu_list) {
|
||||
if (channel->offermsg.child_relid != relid)
|
||||
continue;
|
||||
|
||||
|
|
@ -954,6 +956,8 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu)
|
|||
tasklet_schedule(&channel->callback_event);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue