diff options
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r-- | mm/hugetlb.c | 274 |
1 files changed, 248 insertions, 26 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 1125d818ea06..544f7bcb615e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/io.h> | 24 | #include <asm/io.h> |
25 | 25 | ||
26 | #include <linux/hugetlb.h> | 26 | #include <linux/hugetlb.h> |
27 | #include <linux/node.h> | ||
27 | #include "internal.h" | 28 | #include "internal.h" |
28 | 29 | ||
29 | const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL; | 30 | const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL; |
@@ -1320,39 +1321,71 @@ out: | |||
1320 | static struct kobject *hugepages_kobj; | 1321 | static struct kobject *hugepages_kobj; |
1321 | static struct kobject *hstate_kobjs[HUGE_MAX_HSTATE]; | 1322 | static struct kobject *hstate_kobjs[HUGE_MAX_HSTATE]; |
1322 | 1323 | ||
1323 | static struct hstate *kobj_to_hstate(struct kobject *kobj) | 1324 | static struct hstate *kobj_to_node_hstate(struct kobject *kobj, int *nidp); |
1325 | |||
1326 | static struct hstate *kobj_to_hstate(struct kobject *kobj, int *nidp) | ||
1324 | { | 1327 | { |
1325 | int i; | 1328 | int i; |
1329 | |||
1326 | for (i = 0; i < HUGE_MAX_HSTATE; i++) | 1330 | for (i = 0; i < HUGE_MAX_HSTATE; i++) |
1327 | if (hstate_kobjs[i] == kobj) | 1331 | if (hstate_kobjs[i] == kobj) { |
1332 | if (nidp) | ||
1333 | *nidp = NUMA_NO_NODE; | ||
1328 | return &hstates[i]; | 1334 | return &hstates[i]; |
1329 | BUG(); | 1335 | } |
1330 | return NULL; | 1336 | |
1337 | return kobj_to_node_hstate(kobj, nidp); | ||
1331 | } | 1338 | } |
1332 | 1339 | ||
1333 | static ssize_t nr_hugepages_show_common(struct kobject *kobj, | 1340 | static ssize_t nr_hugepages_show_common(struct kobject *kobj, |
1334 | struct kobj_attribute *attr, char *buf) | 1341 | struct kobj_attribute *attr, char *buf) |
1335 | { | 1342 | { |
1336 | struct hstate *h = kobj_to_hstate(kobj); | 1343 | struct hstate *h; |
1337 | return sprintf(buf, "%lu\n", h->nr_huge_pages); | 1344 | unsigned long nr_huge_pages; |
1345 | int nid; | ||
1346 | |||
1347 | h = kobj_to_hstate(kobj, &nid); | ||
1348 | if (nid == NUMA_NO_NODE) | ||
1349 | nr_huge_pages = h->nr_huge_pages; | ||
1350 | else | ||
1351 | nr_huge_pages = h->nr_huge_pages_node[nid]; | ||
1352 | |||
1353 | return sprintf(buf, "%lu\n", nr_huge_pages); | ||
1338 | } | 1354 | } |
1339 | static ssize_t nr_hugepages_store_common(bool obey_mempolicy, | 1355 | static ssize_t nr_hugepages_store_common(bool obey_mempolicy, |
1340 | struct kobject *kobj, struct kobj_attribute *attr, | 1356 | struct kobject *kobj, struct kobj_attribute *attr, |
1341 | const char *buf, size_t len) | 1357 | const char *buf, size_t len) |
1342 | { | 1358 | { |
1343 | int err; | 1359 | int err; |
1360 | int nid; | ||
1344 | unsigned long count; | 1361 | unsigned long count; |
1345 | struct hstate *h = kobj_to_hstate(kobj); | 1362 | struct hstate *h; |
1346 | NODEMASK_ALLOC(nodemask_t, nodes_allowed); | 1363 | NODEMASK_ALLOC(nodemask_t, nodes_allowed); |
1347 | 1364 | ||
1348 | err = strict_strtoul(buf, 10, &count); | 1365 | err = strict_strtoul(buf, 10, &count); |
1349 | if (err) | 1366 | if (err) |
1350 | return 0; | 1367 | return 0; |
1351 | 1368 | ||
1352 | if (!(obey_mempolicy && init_nodemask_of_mempolicy(nodes_allowed))) { | 1369 | h = kobj_to_hstate(kobj, &nid); |
1353 | NODEMASK_FREE(nodes_allowed); | 1370 | if (nid == NUMA_NO_NODE) { |
1354 | nodes_allowed = &node_online_map; | 1371 | /* |
1355 | } | 1372 | * global hstate attribute |
1373 | */ | ||
1374 | if (!(obey_mempolicy && | ||
1375 | init_nodemask_of_mempolicy(nodes_allowed))) { | ||
1376 | NODEMASK_FREE(nodes_allowed); | ||
1377 | nodes_allowed = &node_states[N_HIGH_MEMORY]; | ||
1378 | } | ||
1379 | } else if (nodes_allowed) { | ||
1380 | /* | ||
1381 | * per node hstate attribute: adjust count to global, | ||
1382 | * but restrict alloc/free to the specified node. | ||
1383 | */ | ||
1384 | count += h->nr_huge_pages - h->nr_huge_pages_node[nid]; | ||
1385 | init_nodemask_of_node(nodes_allowed, nid); | ||
1386 | } else | ||
1387 | nodes_allowed = &node_states[N_HIGH_MEMORY]; | ||
1388 | |||
1356 | h->max_huge_pages = set_max_huge_pages(h, count, nodes_allowed); | 1389 | h->max_huge_pages = set_max_huge_pages(h, count, nodes_allowed); |
1357 | 1390 | ||
1358 | if (nodes_allowed != &node_online_map) | 1391 | if (nodes_allowed != &node_online_map) |
@@ -1398,7 +1431,7 @@ HSTATE_ATTR(nr_hugepages_mempolicy); | |||
1398 | static ssize_t nr_overcommit_hugepages_show(struct kobject *kobj, | 1431 | static ssize_t nr_overcommit_hugepages_show(struct kobject *kobj, |
1399 | struct kobj_attribute *attr, char *buf) | 1432 | struct kobj_attribute *attr, char *buf) |
1400 | { | 1433 | { |
1401 | struct hstate *h = kobj_to_hstate(kobj); | 1434 | struct hstate *h = kobj_to_hstate(kobj, NULL); |
1402 | return sprintf(buf, "%lu\n", h->nr_overcommit_huge_pages); | 1435 | return sprintf(buf, "%lu\n", h->nr_overcommit_huge_pages); |
1403 | } | 1436 | } |
1404 | static ssize_t nr_overcommit_hugepages_store(struct kobject *kobj, | 1437 | static ssize_t nr_overcommit_hugepages_store(struct kobject *kobj, |
@@ -1406,7 +1439,7 @@ static ssize_t nr_overcommit_hugepages_store(struct kobject *kobj, | |||
1406 | { | 1439 | { |
1407 | int err; | 1440 | int err; |
1408 | unsigned long input; | 1441 | unsigned long input; |
1409 | struct hstate *h = kobj_to_hstate(kobj); | 1442 | struct hstate *h = kobj_to_hstate(kobj, NULL); |
1410 | 1443 | ||
1411 | err = strict_strtoul(buf, 10, &input); | 1444 | err = strict_strtoul(buf, 10, &input); |
1412 | if (err) | 1445 | if (err) |
@@ -1423,15 +1456,24 @@ HSTATE_ATTR(nr_overcommit_hugepages); | |||
1423 | static ssize_t free_hugepages_show(struct kobject *kobj, | 1456 | static ssize_t free_hugepages_show(struct kobject *kobj, |
1424 | struct kobj_attribute *attr, char *buf) | 1457 | struct kobj_attribute *attr, char *buf) |
1425 | { | 1458 | { |
1426 | struct hstate *h = kobj_to_hstate(kobj); | 1459 | struct hstate *h; |
1427 | return sprintf(buf, "%lu\n", h->free_huge_pages); | 1460 | unsigned long free_huge_pages; |
1461 | int nid; | ||
1462 | |||
1463 | h = kobj_to_hstate(kobj, &nid); | ||
1464 | if (nid == NUMA_NO_NODE) | ||
1465 | free_huge_pages = h->free_huge_pages; | ||
1466 | else | ||
1467 | free_huge_pages = h->free_huge_pages_node[nid]; | ||
1468 | |||
1469 | return sprintf(buf, "%lu\n", free_huge_pages); | ||
1428 | } | 1470 | } |
1429 | HSTATE_ATTR_RO(free_hugepages); | 1471 | HSTATE_ATTR_RO(free_hugepages); |
1430 | 1472 | ||
1431 | static ssize_t resv_hugepages_show(struct kobject *kobj, | 1473 | static ssize_t resv_hugepages_show(struct kobject *kobj, |
1432 | struct kobj_attribute *attr, char *buf) | 1474 | struct kobj_attribute *attr, char *buf) |
1433 | { | 1475 | { |
1434 | struct hstate *h = kobj_to_hstate(kobj); | 1476 | struct hstate *h = kobj_to_hstate(kobj, NULL); |
1435 | return sprintf(buf, "%lu\n", h->resv_huge_pages); | 1477 | return sprintf(buf, "%lu\n", h->resv_huge_pages); |
1436 | } | 1478 | } |
1437 | HSTATE_ATTR_RO(resv_hugepages); | 1479 | HSTATE_ATTR_RO(resv_hugepages); |
@@ -1439,8 +1481,17 @@ HSTATE_ATTR_RO(resv_hugepages); | |||
1439 | static ssize_t surplus_hugepages_show(struct kobject *kobj, | 1481 | static ssize_t surplus_hugepages_show(struct kobject *kobj, |
1440 | struct kobj_attribute *attr, char *buf) | 1482 | struct kobj_attribute *attr, char *buf) |
1441 | { | 1483 | { |
1442 | struct hstate *h = kobj_to_hstate(kobj); | 1484 | struct hstate *h; |
1443 | return sprintf(buf, "%lu\n", h->surplus_huge_pages); | 1485 | unsigned long surplus_huge_pages; |
1486 | int nid; | ||
1487 | |||
1488 | h = kobj_to_hstate(kobj, &nid); | ||
1489 | if (nid == NUMA_NO_NODE) | ||
1490 | surplus_huge_pages = h->surplus_huge_pages; | ||
1491 | else | ||
1492 | surplus_huge_pages = h->surplus_huge_pages_node[nid]; | ||
1493 | |||
1494 | return sprintf(buf, "%lu\n", surplus_huge_pages); | ||
1444 | } | 1495 | } |
1445 | HSTATE_ATTR_RO(surplus_hugepages); | 1496 | HSTATE_ATTR_RO(surplus_hugepages); |
1446 | 1497 | ||
@@ -1460,19 +1511,21 @@ static struct attribute_group hstate_attr_group = { | |||
1460 | .attrs = hstate_attrs, | 1511 | .attrs = hstate_attrs, |
1461 | }; | 1512 | }; |
1462 | 1513 | ||
1463 | static int __init hugetlb_sysfs_add_hstate(struct hstate *h) | 1514 | static int __init hugetlb_sysfs_add_hstate(struct hstate *h, |
1515 | struct kobject *parent, | ||
1516 | struct kobject **hstate_kobjs, | ||
1517 | struct attribute_group *hstate_attr_group) | ||
1464 | { | 1518 | { |
1465 | int retval; | 1519 | int retval; |
1520 | int hi = h - hstates; | ||
1466 | 1521 | ||
1467 | hstate_kobjs[h - hstates] = kobject_create_and_add(h->name, | 1522 | hstate_kobjs[hi] = kobject_create_and_add(h->name, parent); |
1468 | hugepages_kobj); | 1523 | if (!hstate_kobjs[hi]) |
1469 | if (!hstate_kobjs[h - hstates]) | ||
1470 | return -ENOMEM; | 1524 | return -ENOMEM; |
1471 | 1525 | ||
1472 | retval = sysfs_create_group(hstate_kobjs[h - hstates], | 1526 | retval = sysfs_create_group(hstate_kobjs[hi], hstate_attr_group); |
1473 | &hstate_attr_group); | ||
1474 | if (retval) | 1527 | if (retval) |
1475 | kobject_put(hstate_kobjs[h - hstates]); | 1528 | kobject_put(hstate_kobjs[hi]); |
1476 | 1529 | ||
1477 | return retval; | 1530 | return retval; |
1478 | } | 1531 | } |
@@ -1487,17 +1540,184 @@ static void __init hugetlb_sysfs_init(void) | |||
1487 | return; | 1540 | return; |
1488 | 1541 | ||
1489 | for_each_hstate(h) { | 1542 | for_each_hstate(h) { |
1490 | err = hugetlb_sysfs_add_hstate(h); | 1543 | err = hugetlb_sysfs_add_hstate(h, hugepages_kobj, |
1544 | hstate_kobjs, &hstate_attr_group); | ||
1491 | if (err) | 1545 | if (err) |
1492 | printk(KERN_ERR "Hugetlb: Unable to add hstate %s", | 1546 | printk(KERN_ERR "Hugetlb: Unable to add hstate %s", |
1493 | h->name); | 1547 | h->name); |
1494 | } | 1548 | } |
1495 | } | 1549 | } |
1496 | 1550 | ||
1551 | #ifdef CONFIG_NUMA | ||
1552 | |||
1553 | /* | ||
1554 | * node_hstate/s - associate per node hstate attributes, via their kobjects, | ||
1555 | * with node sysdevs in node_devices[] using a parallel array. The array | ||
1556 | * index of a node sysdev or _hstate == node id. | ||
1557 | * This is here to avoid any static dependency of the node sysdev driver, in | ||
1558 | * the base kernel, on the hugetlb module. | ||
1559 | */ | ||
1560 | struct node_hstate { | ||
1561 | struct kobject *hugepages_kobj; | ||
1562 | struct kobject *hstate_kobjs[HUGE_MAX_HSTATE]; | ||
1563 | }; | ||
1564 | struct node_hstate node_hstates[MAX_NUMNODES]; | ||
1565 | |||
1566 | /* | ||
1567 | * A subset of global hstate attributes for node sysdevs | ||
1568 | */ | ||
1569 | static struct attribute *per_node_hstate_attrs[] = { | ||
1570 | &nr_hugepages_attr.attr, | ||
1571 | &free_hugepages_attr.attr, | ||
1572 | &surplus_hugepages_attr.attr, | ||
1573 | NULL, | ||
1574 | }; | ||
1575 | |||
1576 | static struct attribute_group per_node_hstate_attr_group = { | ||
1577 | .attrs = per_node_hstate_attrs, | ||
1578 | }; | ||
1579 | |||
1580 | /* | ||
1581 | * kobj_to_node_hstate - lookup global hstate for node sysdev hstate attr kobj. | ||
1582 | * Returns node id via non-NULL nidp. | ||
1583 | */ | ||
1584 | static struct hstate *kobj_to_node_hstate(struct kobject *kobj, int *nidp) | ||
1585 | { | ||
1586 | int nid; | ||
1587 | |||
1588 | for (nid = 0; nid < nr_node_ids; nid++) { | ||
1589 | struct node_hstate *nhs = &node_hstates[nid]; | ||
1590 | int i; | ||
1591 | for (i = 0; i < HUGE_MAX_HSTATE; i++) | ||
1592 | if (nhs->hstate_kobjs[i] == kobj) { | ||
1593 | if (nidp) | ||
1594 | *nidp = nid; | ||
1595 | return &hstates[i]; | ||
1596 | } | ||
1597 | } | ||
1598 | |||
1599 | BUG(); | ||
1600 | return NULL; | ||
1601 | } | ||
1602 | |||
1603 | /* | ||
1604 | * Unregister hstate attributes from a single node sysdev. | ||
1605 | * No-op if no hstate attributes attached. | ||
1606 | */ | ||
1607 | void hugetlb_unregister_node(struct node *node) | ||
1608 | { | ||
1609 | struct hstate *h; | ||
1610 | struct node_hstate *nhs = &node_hstates[node->sysdev.id]; | ||
1611 | |||
1612 | if (!nhs->hugepages_kobj) | ||
1613 | return; | ||
1614 | |||
1615 | for_each_hstate(h) | ||
1616 | if (nhs->hstate_kobjs[h - hstates]) { | ||
1617 | kobject_put(nhs->hstate_kobjs[h - hstates]); | ||
1618 | nhs->hstate_kobjs[h - hstates] = NULL; | ||
1619 | } | ||
1620 | |||
1621 | kobject_put(nhs->hugepages_kobj); | ||
1622 | nhs->hugepages_kobj = NULL; | ||
1623 | } | ||
1624 | |||
1625 | /* | ||
1626 | * hugetlb module exit: unregister hstate attributes from node sysdevs | ||
1627 | * that have them. | ||
1628 | */ | ||
1629 | static void hugetlb_unregister_all_nodes(void) | ||
1630 | { | ||
1631 | int nid; | ||
1632 | |||
1633 | /* | ||
1634 | * disable node sysdev registrations. | ||
1635 | */ | ||
1636 | register_hugetlbfs_with_node(NULL, NULL); | ||
1637 | |||
1638 | /* | ||
1639 | * remove hstate attributes from any nodes that have them. | ||
1640 | */ | ||
1641 | for (nid = 0; nid < nr_node_ids; nid++) | ||
1642 | hugetlb_unregister_node(&node_devices[nid]); | ||
1643 | } | ||
1644 | |||
1645 | /* | ||
1646 | * Register hstate attributes for a single node sysdev. | ||
1647 | * No-op if attributes already registered. | ||
1648 | */ | ||
1649 | void hugetlb_register_node(struct node *node) | ||
1650 | { | ||
1651 | struct hstate *h; | ||
1652 | struct node_hstate *nhs = &node_hstates[node->sysdev.id]; | ||
1653 | int err; | ||
1654 | |||
1655 | if (nhs->hugepages_kobj) | ||
1656 | return; /* already allocated */ | ||
1657 | |||
1658 | nhs->hugepages_kobj = kobject_create_and_add("hugepages", | ||
1659 | &node->sysdev.kobj); | ||
1660 | if (!nhs->hugepages_kobj) | ||
1661 | return; | ||
1662 | |||
1663 | for_each_hstate(h) { | ||
1664 | err = hugetlb_sysfs_add_hstate(h, nhs->hugepages_kobj, | ||
1665 | nhs->hstate_kobjs, | ||
1666 | &per_node_hstate_attr_group); | ||
1667 | if (err) { | ||
1668 | printk(KERN_ERR "Hugetlb: Unable to add hstate %s" | ||
1669 | " for node %d\n", | ||
1670 | h->name, node->sysdev.id); | ||
1671 | hugetlb_unregister_node(node); | ||
1672 | break; | ||
1673 | } | ||
1674 | } | ||
1675 | } | ||
1676 | |||
1677 | /* | ||
1678 | * hugetlb init time: register hstate attributes for all registered | ||
1679 | * node sysdevs. All on-line nodes should have registered their | ||
1680 | * associated sysdev by the time the hugetlb module initializes. | ||
1681 | */ | ||
1682 | static void hugetlb_register_all_nodes(void) | ||
1683 | { | ||
1684 | int nid; | ||
1685 | |||
1686 | for (nid = 0; nid < nr_node_ids; nid++) { | ||
1687 | struct node *node = &node_devices[nid]; | ||
1688 | if (node->sysdev.id == nid) | ||
1689 | hugetlb_register_node(node); | ||
1690 | } | ||
1691 | |||
1692 | /* | ||
1693 | * Let the node sysdev driver know we're here so it can | ||
1694 | * [un]register hstate attributes on node hotplug. | ||
1695 | */ | ||
1696 | register_hugetlbfs_with_node(hugetlb_register_node, | ||
1697 | hugetlb_unregister_node); | ||
1698 | } | ||
1699 | #else /* !CONFIG_NUMA */ | ||
1700 | |||
1701 | static struct hstate *kobj_to_node_hstate(struct kobject *kobj, int *nidp) | ||
1702 | { | ||
1703 | BUG(); | ||
1704 | if (nidp) | ||
1705 | *nidp = -1; | ||
1706 | return NULL; | ||
1707 | } | ||
1708 | |||
1709 | static void hugetlb_unregister_all_nodes(void) { } | ||
1710 | |||
1711 | static void hugetlb_register_all_nodes(void) { } | ||
1712 | |||
1713 | #endif | ||
1714 | |||
1497 | static void __exit hugetlb_exit(void) | 1715 | static void __exit hugetlb_exit(void) |
1498 | { | 1716 | { |
1499 | struct hstate *h; | 1717 | struct hstate *h; |
1500 | 1718 | ||
1719 | hugetlb_unregister_all_nodes(); | ||
1720 | |||
1501 | for_each_hstate(h) { | 1721 | for_each_hstate(h) { |
1502 | kobject_put(hstate_kobjs[h - hstates]); | 1722 | kobject_put(hstate_kobjs[h - hstates]); |
1503 | } | 1723 | } |
@@ -1532,6 +1752,8 @@ static int __init hugetlb_init(void) | |||
1532 | 1752 | ||
1533 | hugetlb_sysfs_init(); | 1753 | hugetlb_sysfs_init(); |
1534 | 1754 | ||
1755 | hugetlb_register_all_nodes(); | ||
1756 | |||
1535 | return 0; | 1757 | return 0; |
1536 | } | 1758 | } |
1537 | module_init(hugetlb_init); | 1759 | module_init(hugetlb_init); |