Char/Misc fixes for 4.15-rc3
Here are some small misc driver fixes for 4.15-rc3 to resolve reported issues. Specifically these are: - binder fix for a memory leak - vpd driver fixes for a number of reported problems - hyperv driver fix for memory accesses where it shouldn't be. All of these have been in linux-next for a while. There's also one more MAINTAINERS file update that came in today to get the Android developer's emails correct, which is also in this pull request, that was not in linux-next, but should not be an issue. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWia6IQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ykaKwCgx1lw4qMmetUzjKBX+OMgEkFZo3UAoIL/DLiB ZyMb52XWdP0pScSsFUyn =riSs -----END PGP SIGNATURE----- Merge tag 'char-misc-4.15-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char/misc fixes from Greg KH: "Here are some small misc driver fixes for 4.15-rc3 to resolve reported issues. Specifically these are: - binder fix for a memory leak - vpd driver fixes for a number of reported problems - hyperv driver fix for memory accesses where it shouldn't be. All of these have been in linux-next for a while. There's also one more MAINTAINERS file update that came in today to get the Android developer's emails correct, which is also in this pull request, that was not in linux-next, but should not be an issue" * tag 'char-misc-4.15-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: MAINTAINERS: update Android driver maintainers. firmware: vpd: Fix platform driver and device registration/unregistration firmware: vpd: Tie firmware kobject to device lifetime firmware: vpd: Destroy vpd sections in remove function hv: kvp: Avoid reading past allocated blocks from KVP file Drivers: hv: vmbus: Fix a rescind issue ANDROID: binder: fix transaction leak.
This commit is contained in:
Коммит
6a5e05a47b
|
@ -859,7 +859,8 @@ F: kernel/configs/android*
|
|||
ANDROID DRIVERS
|
||||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
M: Arve Hjønnevåg <arve@android.com>
|
||||
M: Riley Andrews <riandrews@android.com>
|
||||
M: Todd Kjos <tkjos@android.com>
|
||||
M: Martijn Coenen <maco@android.com>
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
|
||||
L: devel@driverdev.osuosl.org
|
||||
S: Supported
|
||||
|
|
|
@ -1947,6 +1947,26 @@ static void binder_send_failed_reply(struct binder_transaction *t,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_cleanup_transaction() - cleans up undelivered transaction
|
||||
* @t: transaction that needs to be cleaned up
|
||||
* @reason: reason the transaction wasn't delivered
|
||||
* @error_code: error to return to caller (if synchronous call)
|
||||
*/
|
||||
static void binder_cleanup_transaction(struct binder_transaction *t,
|
||||
const char *reason,
|
||||
uint32_t error_code)
|
||||
{
|
||||
if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) {
|
||||
binder_send_failed_reply(t, error_code);
|
||||
} else {
|
||||
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
|
||||
"undelivered transaction %d, %s\n",
|
||||
t->debug_id, reason);
|
||||
binder_free_transaction(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_validate_object() - checks for a valid metadata object in a buffer.
|
||||
* @buffer: binder_buffer that we're parsing.
|
||||
|
@ -4015,12 +4035,20 @@ retry:
|
|||
if (put_user(cmd, (uint32_t __user *)ptr)) {
|
||||
if (t_from)
|
||||
binder_thread_dec_tmpref(t_from);
|
||||
|
||||
binder_cleanup_transaction(t, "put_user failed",
|
||||
BR_FAILED_REPLY);
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
ptr += sizeof(uint32_t);
|
||||
if (copy_to_user(ptr, &tr, sizeof(tr))) {
|
||||
if (t_from)
|
||||
binder_thread_dec_tmpref(t_from);
|
||||
|
||||
binder_cleanup_transaction(t, "copy_to_user failed",
|
||||
BR_FAILED_REPLY);
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
ptr += sizeof(tr);
|
||||
|
@ -4090,15 +4118,9 @@ static void binder_release_work(struct binder_proc *proc,
|
|||
struct binder_transaction *t;
|
||||
|
||||
t = container_of(w, struct binder_transaction, work);
|
||||
if (t->buffer->target_node &&
|
||||
!(t->flags & TF_ONE_WAY)) {
|
||||
binder_send_failed_reply(t, BR_DEAD_REPLY);
|
||||
} else {
|
||||
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
|
||||
"undelivered transaction %d\n",
|
||||
t->debug_id);
|
||||
binder_free_transaction(t);
|
||||
}
|
||||
|
||||
binder_cleanup_transaction(t, "process died.",
|
||||
BR_DEAD_REPLY);
|
||||
} break;
|
||||
case BINDER_WORK_RETURN_ERROR: {
|
||||
struct binder_error *e = container_of(
|
||||
|
|
|
@ -295,38 +295,60 @@ static int vpd_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return vpd_sections_init(entry.cbmem_addr);
|
||||
vpd_kobj = kobject_create_and_add("vpd", firmware_kobj);
|
||||
if (!vpd_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = vpd_sections_init(entry.cbmem_addr);
|
||||
if (ret) {
|
||||
kobject_put(vpd_kobj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpd_remove(struct platform_device *pdev)
|
||||
{
|
||||
vpd_section_destroy(&ro_vpd);
|
||||
vpd_section_destroy(&rw_vpd);
|
||||
|
||||
kobject_put(vpd_kobj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vpd_driver = {
|
||||
.probe = vpd_probe,
|
||||
.remove = vpd_remove,
|
||||
.driver = {
|
||||
.name = "vpd",
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *vpd_pdev;
|
||||
|
||||
static int __init vpd_platform_init(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_register_simple("vpd", -1, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
ret = platform_driver_register(&vpd_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vpd_kobj = kobject_create_and_add("vpd", firmware_kobj);
|
||||
if (!vpd_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_driver_register(&vpd_driver);
|
||||
vpd_pdev = platform_device_register_simple("vpd", -1, NULL, 0);
|
||||
if (IS_ERR(vpd_pdev)) {
|
||||
platform_driver_unregister(&vpd_driver);
|
||||
return PTR_ERR(vpd_pdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit vpd_platform_exit(void)
|
||||
{
|
||||
vpd_section_destroy(&ro_vpd);
|
||||
vpd_section_destroy(&rw_vpd);
|
||||
kobject_put(vpd_kobj);
|
||||
platform_device_unregister(vpd_pdev);
|
||||
platform_driver_unregister(&vpd_driver);
|
||||
}
|
||||
|
||||
module_init(vpd_platform_init);
|
||||
|
|
|
@ -659,22 +659,28 @@ void vmbus_close(struct vmbus_channel *channel)
|
|||
*/
|
||||
return;
|
||||
}
|
||||
mutex_lock(&vmbus_connection.channel_mutex);
|
||||
/*
|
||||
* Close all the sub-channels first and then close the
|
||||
* primary channel.
|
||||
*/
|
||||
list_for_each_safe(cur, tmp, &channel->sc_list) {
|
||||
cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
|
||||
vmbus_close_internal(cur_channel);
|
||||
if (cur_channel->rescind) {
|
||||
wait_for_completion(&cur_channel->rescind_event);
|
||||
mutex_lock(&vmbus_connection.channel_mutex);
|
||||
vmbus_close_internal(cur_channel);
|
||||
hv_process_channel_removal(
|
||||
cur_channel->offermsg.child_relid);
|
||||
} else {
|
||||
mutex_lock(&vmbus_connection.channel_mutex);
|
||||
vmbus_close_internal(cur_channel);
|
||||
}
|
||||
mutex_unlock(&vmbus_connection.channel_mutex);
|
||||
}
|
||||
/*
|
||||
* Now close the primary.
|
||||
*/
|
||||
mutex_lock(&vmbus_connection.channel_mutex);
|
||||
vmbus_close_internal(channel);
|
||||
mutex_unlock(&vmbus_connection.channel_mutex);
|
||||
}
|
||||
|
|
|
@ -333,6 +333,7 @@ static struct vmbus_channel *alloc_channel(void)
|
|||
return NULL;
|
||||
|
||||
spin_lock_init(&channel->lock);
|
||||
init_completion(&channel->rescind_event);
|
||||
|
||||
INIT_LIST_HEAD(&channel->sc_list);
|
||||
INIT_LIST_HEAD(&channel->percpu_list);
|
||||
|
@ -898,6 +899,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
|
|||
/*
|
||||
* Now wait for offer handling to complete.
|
||||
*/
|
||||
vmbus_rescind_cleanup(channel);
|
||||
while (READ_ONCE(channel->probe_done) == false) {
|
||||
/*
|
||||
* We wait here until any channel offer is currently
|
||||
|
@ -913,7 +915,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
|
|||
if (channel->device_obj) {
|
||||
if (channel->chn_rescind_callback) {
|
||||
channel->chn_rescind_callback(channel);
|
||||
vmbus_rescind_cleanup(channel);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
@ -922,7 +923,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
|
|||
*/
|
||||
dev = get_device(&channel->device_obj->device);
|
||||
if (dev) {
|
||||
vmbus_rescind_cleanup(channel);
|
||||
vmbus_device_unregister(channel->device_obj);
|
||||
put_device(dev);
|
||||
}
|
||||
|
@ -936,13 +936,14 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
|
|||
* 2. Then close the primary channel.
|
||||
*/
|
||||
mutex_lock(&vmbus_connection.channel_mutex);
|
||||
vmbus_rescind_cleanup(channel);
|
||||
if (channel->state == CHANNEL_OPEN_STATE) {
|
||||
/*
|
||||
* The channel is currently not open;
|
||||
* it is safe for us to cleanup the channel.
|
||||
*/
|
||||
hv_process_channel_removal(rescind->child_relid);
|
||||
} else {
|
||||
complete(&channel->rescind_event);
|
||||
}
|
||||
mutex_unlock(&vmbus_connection.channel_mutex);
|
||||
}
|
||||
|
|
|
@ -708,6 +708,7 @@ struct vmbus_channel {
|
|||
u8 monitor_bit;
|
||||
|
||||
bool rescind; /* got rescind msg */
|
||||
struct completion rescind_event;
|
||||
|
||||
u32 ringbuffer_gpadlhandle;
|
||||
|
||||
|
|
|
@ -193,11 +193,14 @@ static void kvp_update_mem_state(int pool)
|
|||
for (;;) {
|
||||
readp = &record[records_read];
|
||||
records_read += fread(readp, sizeof(struct kvp_record),
|
||||
ENTRIES_PER_BLOCK * num_blocks,
|
||||
filep);
|
||||
ENTRIES_PER_BLOCK * num_blocks - records_read,
|
||||
filep);
|
||||
|
||||
if (ferror(filep)) {
|
||||
syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
|
||||
syslog(LOG_ERR,
|
||||
"Failed to read file, pool: %d; error: %d %s",
|
||||
pool, errno, strerror(errno));
|
||||
kvp_release_lock(pool);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -210,6 +213,7 @@ static void kvp_update_mem_state(int pool)
|
|||
|
||||
if (record == NULL) {
|
||||
syslog(LOG_ERR, "malloc failed");
|
||||
kvp_release_lock(pool);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
continue;
|
||||
|
@ -224,15 +228,11 @@ static void kvp_update_mem_state(int pool)
|
|||
fclose(filep);
|
||||
kvp_release_lock(pool);
|
||||
}
|
||||
|
||||
static int kvp_file_init(void)
|
||||
{
|
||||
int fd;
|
||||
FILE *filep;
|
||||
size_t records_read;
|
||||
char *fname;
|
||||
struct kvp_record *record;
|
||||
struct kvp_record *readp;
|
||||
int num_blocks;
|
||||
int i;
|
||||
int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
|
||||
|
||||
|
@ -246,61 +246,19 @@ static int kvp_file_init(void)
|
|||
|
||||
for (i = 0; i < KVP_POOL_COUNT; i++) {
|
||||
fname = kvp_file_info[i].fname;
|
||||
records_read = 0;
|
||||
num_blocks = 1;
|
||||
sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
|
||||
fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */);
|
||||
|
||||
if (fd == -1)
|
||||
return 1;
|
||||
|
||||
|
||||
filep = fopen(fname, "re");
|
||||
if (!filep) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
record = malloc(alloc_unit * num_blocks);
|
||||
if (record == NULL) {
|
||||
fclose(filep);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
for (;;) {
|
||||
readp = &record[records_read];
|
||||
records_read += fread(readp, sizeof(struct kvp_record),
|
||||
ENTRIES_PER_BLOCK,
|
||||
filep);
|
||||
|
||||
if (ferror(filep)) {
|
||||
syslog(LOG_ERR, "Failed to read file, pool: %d",
|
||||
i);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!feof(filep)) {
|
||||
/*
|
||||
* We have more data to read.
|
||||
*/
|
||||
num_blocks++;
|
||||
record = realloc(record, alloc_unit *
|
||||
num_blocks);
|
||||
if (record == NULL) {
|
||||
fclose(filep);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
kvp_file_info[i].fd = fd;
|
||||
kvp_file_info[i].num_blocks = num_blocks;
|
||||
kvp_file_info[i].records = record;
|
||||
kvp_file_info[i].num_records = records_read;
|
||||
fclose(filep);
|
||||
|
||||
kvp_file_info[i].num_blocks = 1;
|
||||
kvp_file_info[i].records = malloc(alloc_unit);
|
||||
if (kvp_file_info[i].records == NULL)
|
||||
return 1;
|
||||
kvp_file_info[i].num_records = 0;
|
||||
kvp_update_mem_state(i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче