|
Description
|
Found by code inspection. In ldc_mem_bind_handle, the first time a memory handle is bound to a channel, the map table must be allocated.
From ldc_mem_bind_handle(),
285 /*
286 * If this channel is binding a memory handle for the
287 * first time allocate it a memory map table and initialize it
288 */
289 if ((mtbl = ldcp->mtbl) == NULL) {
290
291 mutex_enter(&ldcp->lock);
292
293 /* Allocate and initialize the map table structure */
294 mtbl = kmem_zalloc(sizeof (ldc_mtbl_t), KM_SLEEP);
...
322 /* register table for this channel */
323 rv = hv_ldc_set_map_table(ldcp->id,
324 va_to_pa(mtbl->table), mtbl->num_entries);
...
340 ldcp->mtbl = mtbl;
341 mutex_exit(&ldcp->lock);
...
346 }
...
476 /* update entry in table */
477 mtbl->table[index].entry = tmp_mte;
The problem is that the channel lock is acquired after the check for ldcp->mtbl == NULL. With competing threads, each trying to ldc_mem_bind_handle() different handles to the same channel at the same time, more than one thread could find ldcp->mtbl == NULL. As a result, more than one map table will be allocated (wasting memory) and threads that find ldcp->mtbl == NULL and obtain the channel lock later, will overwrite earlier threads hv_ldc_set_map_table() call. The earlier threads' map table entries will not be found by the HV since later threads will have overwritten the map table. This will cause the importing domain's calls to ldc_mem_map() to fail.
|