Changes in kernel/generic/src/mm/as.c [97bdb4a:8f80c77] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/mm/as.c
r97bdb4a r8f80c77 116 116 as_t *AS_KERNEL = NULL; 117 117 118 NO_TRACE static int as_constructor(void *obj, unsigned int flags) 118 static unsigned int area_flags_to_page_flags(unsigned int); 119 static as_area_t *find_area_and_lock(as_t *, uintptr_t); 120 static bool check_area_conflicts(as_t *, uintptr_t, size_t, as_area_t *); 121 static void sh_info_remove_reference(share_info_t *); 122 123 static int as_constructor(void *obj, unsigned int flags) 119 124 { 120 125 as_t *as = (as_t *) obj; … … 128 133 } 129 134 130 NO_TRACEstatic size_t as_destructor(void *obj)135 static size_t as_destructor(void *obj) 131 136 { 132 137 as_t *as = (as_t *) obj; … … 234 239 235 240 spinlock_unlock(&asidlock); 236 interrupts_restore(ipl);237 238 241 239 242 /* … … 263 266 #endif 264 267 268 interrupts_restore(ipl); 269 265 270 slab_free(as_slab, as); 266 271 } … … 274 279 * 275 280 */ 276 NO_TRACEvoid as_hold(as_t *as)281 void as_hold(as_t *as) 277 282 { 278 283 atomic_inc(&as->refcount); … … 287 292 * 288 293 */ 289 NO_TRACEvoid as_release(as_t *as)294 void as_release(as_t *as) 290 295 { 291 296 if (atomic_predec(&as->refcount) == 0) 292 297 as_destroy(as); 293 }294 295 /** Check area conflicts with other areas.296 *297 * @param as Address space.298 * @param va Starting virtual address of the area being tested.299 * @param size Size of the area being tested.300 * @param avoid_area Do not touch this area.301 *302 * @return True if there is no conflict, false otherwise.303 *304 */305 NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,306 as_area_t *avoid_area)307 {308 ASSERT(mutex_locked(&as->lock));309 310 /*311 * We don't want any area to have conflicts with NULL page.312 *313 */314 if (overlaps(va, size, NULL, PAGE_SIZE))315 return false;316 317 /*318 * The leaf node is found in O(log n), where n is proportional to319 * the number of address space areas belonging to as.320 * The check for conflicts is then attempted on the rightmost321 * record in the left neighbour, the leftmost record in the right322 * neighbour and all records in the leaf node itself.323 *324 */325 btree_node_t *leaf;326 as_area_t *area =327 (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);328 if (area) {329 if (area != avoid_area)330 return false;331 }332 333 /* First, check the two border cases. */334 btree_node_t *node =335 btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);336 if (node) {337 area = (as_area_t *) node->value[node->keys - 1];338 339 mutex_lock(&area->lock);340 341 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {342 mutex_unlock(&area->lock);343 return false;344 }345 346 mutex_unlock(&area->lock);347 }348 349 node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);350 if (node) {351 area = (as_area_t *) node->value[0];352 353 mutex_lock(&area->lock);354 355 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {356 mutex_unlock(&area->lock);357 return false;358 }359 360 mutex_unlock(&area->lock);361 }362 363 /* Second, check the leaf node. */364 btree_key_t i;365 for (i = 0; i < leaf->keys; i++) {366 area = (as_area_t *) leaf->value[i];367 368 if (area == avoid_area)369 continue;370 371 mutex_lock(&area->lock);372 373 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {374 mutex_unlock(&area->lock);375 return false;376 }377 378 mutex_unlock(&area->lock);379 }380 381 /*382 * So far, the area does not conflict with other areas.383 * Check if it doesn't conflict with kernel address space.384 *385 */386 if (!KERNEL_ADDRESS_SPACE_SHADOWED) {387 return !overlaps(va, size,388 KERNEL_ADDRESS_SPACE_START,389 KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);390 }391 392 return true;393 298 } 394 299 … … 422 327 return NULL; 423 328 329 ipl_t ipl = interrupts_disable(); 424 330 mutex_lock(&as->lock); 425 331 426 332 if (!check_area_conflicts(as, base, size, NULL)) { 427 333 mutex_unlock(&as->lock); 334 interrupts_restore(ipl); 428 335 return NULL; 429 336 } … … 450 357 451 358 mutex_unlock(&as->lock); 359 interrupts_restore(ipl); 452 360 453 361 return area; 454 }455 456 /** Find address space area and lock it.457 *458 * @param as Address space.459 * @param va Virtual address.460 *461 * @return Locked address space area containing va on success or462 * NULL on failure.463 *464 */465 NO_TRACE static as_area_t *find_area_and_lock(as_t *as, uintptr_t va)466 {467 ASSERT(mutex_locked(&as->lock));468 469 btree_node_t *leaf;470 as_area_t *area = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);471 if (area) {472 /* va is the base address of an address space area */473 mutex_lock(&area->lock);474 return area;475 }476 477 /*478 * Search the leaf node and the righmost record of its left neighbour479 * to find out whether this is a miss or va belongs to an address480 * space area found there.481 *482 */483 484 /* First, search the leaf node itself. */485 btree_key_t i;486 487 for (i = 0; i < leaf->keys; i++) {488 area = (as_area_t *) leaf->value[i];489 490 mutex_lock(&area->lock);491 492 if ((area->base <= va) && (va < area->base + area->pages * PAGE_SIZE))493 return area;494 495 mutex_unlock(&area->lock);496 }497 498 /*499 * Second, locate the left neighbour and test its last record.500 * Because of its position in the B+tree, it must have base < va.501 *502 */503 btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);504 if (lnode) {505 area = (as_area_t *) lnode->value[lnode->keys - 1];506 507 mutex_lock(&area->lock);508 509 if (va < area->base + area->pages * PAGE_SIZE)510 return area;511 512 mutex_unlock(&area->lock);513 }514 515 return NULL;516 362 } 517 363 … … 530 376 int as_area_resize(as_t *as, uintptr_t address, size_t size, unsigned int flags) 531 377 { 378 ipl_t ipl = interrupts_disable(); 532 379 mutex_lock(&as->lock); 533 380 … … 539 386 if (!area) { 540 387 mutex_unlock(&as->lock); 388 interrupts_restore(ipl); 541 389 return ENOENT; 542 390 } … … 550 398 mutex_unlock(&area->lock); 551 399 mutex_unlock(&as->lock); 400 interrupts_restore(ipl); 552 401 return ENOTSUP; 553 402 } … … 561 410 mutex_unlock(&area->lock); 562 411 mutex_unlock(&as->lock); 412 interrupts_restore(ipl); 563 413 return ENOTSUP; 564 414 } … … 572 422 mutex_unlock(&area->lock); 573 423 mutex_unlock(&as->lock); 424 interrupts_restore(ipl); 574 425 return EPERM; 575 426 } … … 590 441 * 591 442 */ 592 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid,593 area->base +pages * PAGE_SIZE, area->pages - pages);443 tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base + 444 pages * PAGE_SIZE, area->pages - pages); 594 445 595 446 /* … … 685 536 as_invalidate_translation_cache(as, area->base + 686 537 pages * PAGE_SIZE, area->pages - pages); 687 tlb_shootdown_finalize( ipl);538 tlb_shootdown_finalize(); 688 539 689 540 page_table_unlock(as, false); … … 698 549 mutex_unlock(&area->lock); 699 550 mutex_unlock(&as->lock); 551 interrupts_restore(ipl); 700 552 return EADDRNOTAVAIL; 701 553 } … … 706 558 mutex_unlock(&area->lock); 707 559 mutex_unlock(&as->lock); 560 interrupts_restore(ipl); 708 561 709 562 return 0; 710 }711 712 /** Remove reference to address space area share info.713 *714 * If the reference count drops to 0, the sh_info is deallocated.715 *716 * @param sh_info Pointer to address space area share info.717 *718 */719 NO_TRACE static void sh_info_remove_reference(share_info_t *sh_info)720 {721 bool dealloc = false;722 723 mutex_lock(&sh_info->lock);724 ASSERT(sh_info->refcount);725 726 if (--sh_info->refcount == 0) {727 dealloc = true;728 link_t *cur;729 730 /*731 * Now walk carefully the pagemap B+tree and free/remove732 * reference from all frames found there.733 */734 for (cur = sh_info->pagemap.leaf_head.next;735 cur != &sh_info->pagemap.leaf_head; cur = cur->next) {736 btree_node_t *node737 = list_get_instance(cur, btree_node_t, leaf_link);738 btree_key_t i;739 740 for (i = 0; i < node->keys; i++)741 frame_free((uintptr_t) node->value[i]);742 }743 744 }745 mutex_unlock(&sh_info->lock);746 747 if (dealloc) {748 btree_destroy(&sh_info->pagemap);749 free(sh_info);750 }751 563 } 752 564 … … 761 573 int as_area_destroy(as_t *as, uintptr_t address) 762 574 { 575 ipl_t ipl = interrupts_disable(); 763 576 mutex_lock(&as->lock); 764 577 … … 766 579 if (!area) { 767 580 mutex_unlock(&as->lock); 581 interrupts_restore(ipl); 768 582 return ENOENT; 769 583 } … … 776 590 * Start TLB shootdown sequence. 777 591 */ 778 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, 779 area->pages); 592 tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, area->pages); 780 593 781 594 /* … … 824 637 */ 825 638 as_invalidate_translation_cache(as, area->base, area->pages); 826 tlb_shootdown_finalize( ipl);639 tlb_shootdown_finalize(); 827 640 828 641 page_table_unlock(as, false); … … 846 659 847 660 mutex_unlock(&as->lock); 661 interrupts_restore(ipl); 848 662 return 0; 849 663 } … … 876 690 as_t *dst_as, uintptr_t dst_base, unsigned int dst_flags_mask) 877 691 { 692 ipl_t ipl = interrupts_disable(); 878 693 mutex_lock(&src_as->lock); 879 694 as_area_t *src_area = find_area_and_lock(src_as, src_base); … … 884 699 */ 885 700 mutex_unlock(&src_as->lock); 701 interrupts_restore(ipl); 886 702 return ENOENT; 887 703 } … … 895 711 mutex_unlock(&src_area->lock); 896 712 mutex_unlock(&src_as->lock); 713 interrupts_restore(ipl); 897 714 return ENOTSUP; 898 715 } … … 911 728 mutex_unlock(&src_area->lock); 912 729 mutex_unlock(&src_as->lock); 730 interrupts_restore(ipl); 913 731 return EPERM; 914 732 } … … 959 777 sh_info_remove_reference(sh_info); 960 778 779 interrupts_restore(ipl); 961 780 return ENOMEM; 962 781 } … … 975 794 mutex_unlock(&dst_as->lock); 976 795 796 interrupts_restore(ipl); 797 977 798 return 0; 978 799 } … … 987 808 * 988 809 */ 989 NO_TRACEbool as_area_check_access(as_area_t *area, pf_access_t access)810 bool as_area_check_access(as_area_t *area, pf_access_t access) 990 811 { 991 812 int flagmap[] = { … … 995 816 }; 996 817 818 ASSERT(interrupts_disabled()); 997 819 ASSERT(mutex_locked(&area->lock)); 998 820 … … 1001 823 1002 824 return true; 1003 }1004 1005 /** Convert address space area flags to page flags.1006 *1007 * @param aflags Flags of some address space area.1008 *1009 * @return Flags to be passed to page_mapping_insert().1010 *1011 */1012 NO_TRACE static unsigned int area_flags_to_page_flags(unsigned int aflags)1013 {1014 unsigned int flags = PAGE_USER | PAGE_PRESENT;1015 1016 if (aflags & AS_AREA_READ)1017 flags |= PAGE_READ;1018 1019 if (aflags & AS_AREA_WRITE)1020 flags |= PAGE_WRITE;1021 1022 if (aflags & AS_AREA_EXEC)1023 flags |= PAGE_EXEC;1024 1025 if (aflags & AS_AREA_CACHEABLE)1026 flags |= PAGE_CACHEABLE;1027 1028 return flags;1029 825 } 1030 826 … … 1048 844 unsigned int page_flags = area_flags_to_page_flags(flags); 1049 845 846 ipl_t ipl = interrupts_disable(); 1050 847 mutex_lock(&as->lock); 1051 848 … … 1053 850 if (!area) { 1054 851 mutex_unlock(&as->lock); 852 interrupts_restore(ipl); 1055 853 return ENOENT; 1056 854 } … … 1061 859 mutex_unlock(&area->lock); 1062 860 mutex_unlock(&as->lock); 861 interrupts_restore(ipl); 1063 862 return ENOTSUP; 1064 863 } … … 1090 889 * 1091 890 */ 1092 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, 1093 area->pages); 891 tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, area->pages); 1094 892 1095 893 /* … … 1138 936 */ 1139 937 as_invalidate_translation_cache(as, area->base, area->pages); 1140 tlb_shootdown_finalize( ipl);938 tlb_shootdown_finalize(); 1141 939 1142 940 page_table_unlock(as, false); … … 1180 978 mutex_unlock(&area->lock); 1181 979 mutex_unlock(&as->lock); 980 interrupts_restore(ipl); 1182 981 1183 982 return 0; … … 1385 1184 } 1386 1185 1186 /** Convert address space area flags to page flags. 1187 * 1188 * @param aflags Flags of some address space area. 1189 * 1190 * @return Flags to be passed to page_mapping_insert(). 1191 * 1192 */ 1193 unsigned int area_flags_to_page_flags(unsigned int aflags) 1194 { 1195 unsigned int flags = PAGE_USER | PAGE_PRESENT; 1196 1197 if (aflags & AS_AREA_READ) 1198 flags |= PAGE_READ; 1199 1200 if (aflags & AS_AREA_WRITE) 1201 flags |= PAGE_WRITE; 1202 1203 if (aflags & AS_AREA_EXEC) 1204 flags |= PAGE_EXEC; 1205 1206 if (aflags & AS_AREA_CACHEABLE) 1207 flags |= PAGE_CACHEABLE; 1208 1209 return flags; 1210 } 1211 1387 1212 /** Compute flags for virtual address translation subsytem. 1388 1213 * … … 1392 1217 * 1393 1218 */ 1394 NO_TRACE unsigned int as_area_get_flags(as_area_t *area) 1395 { 1219 unsigned int as_area_get_flags(as_area_t *area) 1220 { 1221 ASSERT(interrupts_disabled()); 1396 1222 ASSERT(mutex_locked(&area->lock)); 1397 1223 … … 1410 1236 * 1411 1237 */ 1412 NO_TRACEpte_t *page_table_create(unsigned int flags)1238 pte_t *page_table_create(unsigned int flags) 1413 1239 { 1414 1240 ASSERT(as_operations); … … 1425 1251 * 1426 1252 */ 1427 NO_TRACEvoid page_table_destroy(pte_t *page_table)1253 void page_table_destroy(pte_t *page_table) 1428 1254 { 1429 1255 ASSERT(as_operations); … … 1446 1272 * 1447 1273 */ 1448 NO_TRACEvoid page_table_lock(as_t *as, bool lock)1274 void page_table_lock(as_t *as, bool lock) 1449 1275 { 1450 1276 ASSERT(as_operations); … … 1460 1286 * 1461 1287 */ 1462 NO_TRACEvoid page_table_unlock(as_t *as, bool unlock)1288 void page_table_unlock(as_t *as, bool unlock) 1463 1289 { 1464 1290 ASSERT(as_operations); … … 1470 1296 /** Test whether page tables are locked. 1471 1297 * 1472 * @param as 1473 * 1474 * @return 1475 * 1476 */ 1477 NO_TRACEbool page_table_locked(as_t *as)1298 * @param as Address space where the page tables belong. 1299 * 1300 * @return True if the page tables belonging to the address soace 1301 * are locked, otherwise false. 1302 */ 1303 bool page_table_locked(as_t *as) 1478 1304 { 1479 1305 ASSERT(as_operations); … … 1483 1309 } 1484 1310 1311 1312 /** Find address space area and lock it. 1313 * 1314 * @param as Address space. 1315 * @param va Virtual address. 1316 * 1317 * @return Locked address space area containing va on success or 1318 * NULL on failure. 1319 * 1320 */ 1321 as_area_t *find_area_and_lock(as_t *as, uintptr_t va) 1322 { 1323 ASSERT(interrupts_disabled()); 1324 ASSERT(mutex_locked(&as->lock)); 1325 1326 btree_node_t *leaf; 1327 as_area_t *area = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf); 1328 if (area) { 1329 /* va is the base address of an address space area */ 1330 mutex_lock(&area->lock); 1331 return area; 1332 } 1333 1334 /* 1335 * Search the leaf node and the righmost record of its left neighbour 1336 * to find out whether this is a miss or va belongs to an address 1337 * space area found there. 1338 * 1339 */ 1340 1341 /* First, search the leaf node itself. */ 1342 btree_key_t i; 1343 1344 for (i = 0; i < leaf->keys; i++) { 1345 area = (as_area_t *) leaf->value[i]; 1346 1347 mutex_lock(&area->lock); 1348 1349 if ((area->base <= va) && (va < area->base + area->pages * PAGE_SIZE)) 1350 return area; 1351 1352 mutex_unlock(&area->lock); 1353 } 1354 1355 /* 1356 * Second, locate the left neighbour and test its last record. 1357 * Because of its position in the B+tree, it must have base < va. 1358 * 1359 */ 1360 btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf); 1361 if (lnode) { 1362 area = (as_area_t *) lnode->value[lnode->keys - 1]; 1363 1364 mutex_lock(&area->lock); 1365 1366 if (va < area->base + area->pages * PAGE_SIZE) 1367 return area; 1368 1369 mutex_unlock(&area->lock); 1370 } 1371 1372 return NULL; 1373 } 1374 1375 /** Check area conflicts with other areas. 1376 * 1377 * @param as Address space. 1378 * @param va Starting virtual address of the area being tested. 1379 * @param size Size of the area being tested. 1380 * @param avoid_area Do not touch this area. 1381 * 1382 * @return True if there is no conflict, false otherwise. 1383 * 1384 */ 1385 bool check_area_conflicts(as_t *as, uintptr_t va, size_t size, 1386 as_area_t *avoid_area) 1387 { 1388 ASSERT(interrupts_disabled()); 1389 ASSERT(mutex_locked(&as->lock)); 1390 1391 /* 1392 * We don't want any area to have conflicts with NULL page. 1393 * 1394 */ 1395 if (overlaps(va, size, NULL, PAGE_SIZE)) 1396 return false; 1397 1398 /* 1399 * The leaf node is found in O(log n), where n is proportional to 1400 * the number of address space areas belonging to as. 1401 * The check for conflicts is then attempted on the rightmost 1402 * record in the left neighbour, the leftmost record in the right 1403 * neighbour and all records in the leaf node itself. 1404 * 1405 */ 1406 btree_node_t *leaf; 1407 as_area_t *area = 1408 (as_area_t *) btree_search(&as->as_area_btree, va, &leaf); 1409 if (area) { 1410 if (area != avoid_area) 1411 return false; 1412 } 1413 1414 /* First, check the two border cases. */ 1415 btree_node_t *node = 1416 btree_leaf_node_left_neighbour(&as->as_area_btree, leaf); 1417 if (node) { 1418 area = (as_area_t *) node->value[node->keys - 1]; 1419 1420 mutex_lock(&area->lock); 1421 1422 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) { 1423 mutex_unlock(&area->lock); 1424 return false; 1425 } 1426 1427 mutex_unlock(&area->lock); 1428 } 1429 1430 node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf); 1431 if (node) { 1432 area = (as_area_t *) node->value[0]; 1433 1434 mutex_lock(&area->lock); 1435 1436 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) { 1437 mutex_unlock(&area->lock); 1438 return false; 1439 } 1440 1441 mutex_unlock(&area->lock); 1442 } 1443 1444 /* Second, check the leaf node. */ 1445 btree_key_t i; 1446 for (i = 0; i < leaf->keys; i++) { 1447 area = (as_area_t *) leaf->value[i]; 1448 1449 if (area == avoid_area) 1450 continue; 1451 1452 mutex_lock(&area->lock); 1453 1454 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) { 1455 mutex_unlock(&area->lock); 1456 return false; 1457 } 1458 1459 mutex_unlock(&area->lock); 1460 } 1461 1462 /* 1463 * So far, the area does not conflict with other areas. 1464 * Check if it doesn't conflict with kernel address space. 1465 * 1466 */ 1467 if (!KERNEL_ADDRESS_SPACE_SHADOWED) { 1468 return !overlaps(va, size, 1469 KERNEL_ADDRESS_SPACE_START, 1470 KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START); 1471 } 1472 1473 return true; 1474 } 1475 1485 1476 /** Return size of the address space area with given base. 1486 1477 * … … 1495 1486 size_t size; 1496 1487 1488 ipl_t ipl = interrupts_disable(); 1497 1489 page_table_lock(AS, true); 1498 1490 as_area_t *src_area = find_area_and_lock(AS, base); … … 1505 1497 1506 1498 page_table_unlock(AS, true); 1499 interrupts_restore(ipl); 1507 1500 return size; 1508 1501 } … … 1995 1988 } 1996 1989 1990 /** Remove reference to address space area share info. 1991 * 1992 * If the reference count drops to 0, the sh_info is deallocated. 1993 * 1994 * @param sh_info Pointer to address space area share info. 1995 * 1996 */ 1997 void sh_info_remove_reference(share_info_t *sh_info) 1998 { 1999 bool dealloc = false; 2000 2001 mutex_lock(&sh_info->lock); 2002 ASSERT(sh_info->refcount); 2003 2004 if (--sh_info->refcount == 0) { 2005 dealloc = true; 2006 link_t *cur; 2007 2008 /* 2009 * Now walk carefully the pagemap B+tree and free/remove 2010 * reference from all frames found there. 2011 */ 2012 for (cur = sh_info->pagemap.leaf_head.next; 2013 cur != &sh_info->pagemap.leaf_head; cur = cur->next) { 2014 btree_node_t *node 2015 = list_get_instance(cur, btree_node_t, leaf_link); 2016 btree_key_t i; 2017 2018 for (i = 0; i < node->keys; i++) 2019 frame_free((uintptr_t) node->value[i]); 2020 } 2021 2022 } 2023 mutex_unlock(&sh_info->lock); 2024 2025 if (dealloc) { 2026 btree_destroy(&sh_info->pagemap); 2027 free(sh_info); 2028 } 2029 } 2030 1997 2031 /* 1998 2032 * Address space related syscalls. … … 2036 2070 void as_get_area_info(as_t *as, as_area_info_t **obuf, size_t *osize) 2037 2071 { 2072 ipl_t ipl = interrupts_disable(); 2038 2073 mutex_lock(&as->lock); 2039 2074 … … 2079 2114 2080 2115 mutex_unlock(&as->lock); 2116 interrupts_restore(ipl); 2081 2117 2082 2118 *obuf = info; … … 2091 2127 void as_print(as_t *as) 2092 2128 { 2129 ipl_t ipl = interrupts_disable(); 2093 2130 mutex_lock(&as->lock); 2094 2131 … … 2113 2150 2114 2151 mutex_unlock(&as->lock); 2152 interrupts_restore(ipl); 2115 2153 } 2116 2154
Note:
See TracChangeset
for help on using the changeset viewer.