Codebase list nvidia-persistenced / b20f8d5
495.29.05 Aaron Plattner 2 years ago
5 changed file(s) with 49 addition(s) and 113 deletion(s). Raw diff Collapse all Expand all
00 /*
1 * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
1 * SPDX-FileCopyrightText: Copyright (c) 2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2 * SPDX-License-Identifier: MIT
23 *
34 * Permission is hereby granted, free of charge, to any person obtaining a
45 * copy of this software and associated documentation files (the "Software"),
1213 *
1314 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1415 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1617 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1718 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1819 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00 /*
1 * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
1 * SPDX-FileCopyrightText: Copyright (c) 2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2 * SPDX-License-Identifier: MIT
23 *
34 * Permission is hereby granted, free of charge, to any person obtaining a
45 * copy of this software and associated documentation files (the "Software"),
1213 *
1314 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1415 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1617 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1718 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1819 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
5050 #define MEMORY_PATH_FMT "/sys/devices/system/memory"
5151 #define MEMORY_HARD_OFFLINE_PATH_FMT MEMORY_PATH_FMT "/hard_offline_page"
5252 #define MEMORY_PROBE_PATH_FMT MEMORY_PATH_FMT "/probe"
53 #define MEMBLK_DIR_PATH_FMT MEMORY_PATH_FMT "/memory%d"
53 #define MEMBLK_FILE_FMT "memory%d"
54 #define MEMBLK_DIR_PATH_FMT MEMORY_PATH_FMT "/" MEMBLK_FILE_FMT
5455 #define MEMBLK_STATE_PATH_FMT MEMBLK_DIR_PATH_FMT "/state"
5556 #define MEMBLK_VALID_ZONES_PATH_FMT MEMBLK_DIR_PATH_FMT "/valid_zones"
5657 #define NID_PATH_FMT "/sys/devices/system/node/node%d"
327328 return (sscanf(dirname, "memory%" PRIu32, block_id) == 1) ? 0 : -EINVAL;
328329 }
329330
330 /*
331 * Looks through NUMA nodes, finding the upper and lower bounds, and returns
332 * those. The assumption is that the nodes are physically contiguous, so that
333 * the intervening nodes do not need to be explicitly returned.
334 */
335 static
336 int gather_memblock_ids_for_node(uint32_t node_id, uint32_t *memblock_start_id,
337 uint32_t *memblock_end_id)
338 {
339 DIR *dir_ptr;
340 int status = 0;
341 struct dirent *dir_entry;
342 char numa_file_path[BUF_SIZE];
343 uint32_t start_id = UINT32_MAX;
344 uint32_t end_id = 0;
345
346 sprintf(numa_file_path, NID_PATH_FMT, node_id);
347
348 dir_ptr = opendir(numa_file_path);
349 if (!dir_ptr) {
350 syslog(LOG_ERR, "NUMA: Failed to open directory %s: %s\n",
351 numa_file_path, strerror(errno));
352 return -errno;
353 }
354
355 /* Iterate through the node directory and get the memblock id */
356 while ((dir_entry = readdir(dir_ptr)) != NULL) {
357 uint32_t memblock_id = 0;
358
359 /* Skip entries that are not a memory node */
360 if (get_memblock_id_from_dirname(dir_entry->d_name, &memblock_id) < 0) {
361 continue;
362 }
363
364 if (memblock_id == 0) {
365 syslog(LOG_ERR,
366 "NUMA: Failed to get memblock id while iterating through %s\n",
367 numa_file_path);
368 goto cleanup;
369 }
370
371 SYSLOG_VERBOSE(LOG_DEBUG, "NUMA: Found memblock entry %"PRIu32"\n",
372 memblock_id);
373
374 /* Record the smallest and largest assigned memblock IDs */
375 start_id = (start_id < memblock_id) ? start_id : memblock_id;
376 end_id = (end_id > memblock_id) ? end_id : memblock_id;
377 }
378
379 /*
380 * If the wrong directory was specified, readdir can return success,
381 * even though it never iterated any files in the directory. Make that case
382 * also an error, by verifying that start_id has been set.
383 */
384 if (start_id == UINT32_MAX) {
385 syslog(LOG_ERR, "NUMA: Failed to find any files in %s", numa_file_path);
386 status = -ENOENT;
387 goto cleanup;
388 }
389
390 *memblock_start_id = start_id;
391 *memblock_end_id = end_id;
392
393 SYSLOG_VERBOSE(LOG_DEBUG,
394 "NUMA: Found memblock start id: %"PRIu32
395 " and end id: %"PRIu32"\n",
396 *memblock_start_id, *memblock_end_id);
397
398 cleanup:
399 closedir(dir_ptr);
400 return status;
401 }
402
403 static
404 int change_numa_node_state(uint32_t node_id, uint64_t region_gpu_size,
405 uint64_t memblock_size, mem_state_t new_state)
331 static
332 int change_numa_node_state(uint32_t node_id,
333 uint64_t base_addr,
334 uint64_t region_gpu_size,
335 uint64_t memblock_size,
336 mem_state_t new_state)
406337 {
407338 uint32_t memblock_id;
408339 int status = 0, err_status = 0;
409340 uint64_t blocks_changed = 0;
410 uint32_t memblock_start_id = 0;
411 uint32_t memblock_end_id = 0;
412
413 status = gather_memblock_ids_for_node(node_id, &memblock_start_id,
414 &memblock_end_id);
415 if (status < 0) {
416 syslog(LOG_ERR, "NUMA: Failed to get all memblock ID's for node%d\n",
417 node_id);
418 return status;
419 }
420
421 if (memblock_start_id > memblock_end_id) {
422 syslog(LOG_ERR, "NUMA: Invalid memblock IDs were found for node%d\n",
423 node_id);
424 return -EINVAL;
425 }
341 uint32_t memblock_start_id = base_addr / memblock_size;
342 uint32_t memblock_end_id = (base_addr + region_gpu_size) / memblock_size - 1;
426343
427344 SYSLOG_VERBOSE(LOG_DEBUG,
428345 "NUMA: memblock ID range: %"PRIu32"-%"PRIu32
531448 syslog(LOG_ERR, "NUMA: Probe ranges not aligned to memblock size!\n");
532449 return -EFAULT;
533450 }
451
452 if (access(MEMORY_PROBE_PATH_FMT, F_OK) != 0 && errno == ENOENT)
453 /*
454 * It is not an error when the 'probe' file is not found, since this
455 * situation is normal for systems where the driver handles probe of
456 * the NUMA memory.
457 */
458 goto done;
534459
535460 for (start_addr = probe_base_addr;
536461 start_addr + memblock_size <= numa_end_addr;
618543 }
619544
620545 status = change_numa_node_state(numa_info_params.nid,
546 numa_info_params.numa_mem_addr,
621547 numa_info_params.numa_mem_size,
622548 numa_info_params.memblock_size,
623549 NV_IOCTL_NUMA_STATUS_OFFLINE);
649575 }
650576
651577 #define MEMORY_AUTO_ONLINE_WARNING_FMT \
652 "NUMA: %s state is online and the default zone is not movable (%s).\n" \
578 "NUMA: " MEMBLK_FILE_FMT " state is online and the default zone is not movable (%s).\n" \
653579 "This likely means that some non-NVIDIA software has auto-onlined\n" \
654580 "the device memory before nvidia-persistenced could. Please check\n" \
655581 "if the CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE kernel config option\n" \
657583 "/lib/udev/rules.d/."
658584
659585 static
660 int check_memory_auto_online(uint32_t node_id, NvCfgBool *auto_online_success)
586 int check_memory_auto_online(uint32_t node_id,
587 uint64_t base_addr,
588 uint64_t region_gpu_size,
589 uint64_t memblock_size,
590 NvCfgBool *auto_online_success)
661591 {
662592 DIR *dir_ptr;
663593 int status = 0;
664 struct dirent *dir_entry;
665594 char read_buf[BUF_SIZE];
666595 char numa_file_path[BUF_SIZE];
667596 char memory_file_path[BUF_SIZE];
668597 int num_memory_node_in_dir = 0;
669598 int num_memory_online_movable = 0;
599 uint32_t block_id;
600 uint32_t memblock_start_id = base_addr / memblock_size;
601 uint32_t memblock_end_id = (base_addr + region_gpu_size) / memblock_size - 1;
670602
671603 *auto_online_success = NVCFG_FALSE;
672604
679611 return -errno;
680612 }
681613
682 /* Iterate through the node directory */
683 while ((dir_entry = readdir(dir_ptr)) != NULL) {
684 uint32_t block_id;
685
686 /* Skip entries that are not a memory node */
687 if (get_memblock_id_from_dirname(dir_entry->d_name, &block_id) < 0) {
688 continue;
689 }
614 /* Iterate through the blocks */
615 for (block_id = memblock_start_id; block_id <= memblock_end_id; block_id++) {
690616
691617 num_memory_node_in_dir++;
692618
696622 read_buf, sizeof(read_buf));
697623 if (status < 0) {
698624 syslog(LOG_ERR,
699 "NUMA: Failed to read %s state\n", dir_entry->d_name);
625 "NUMA: Failed to read " MEMBLK_FILE_FMT " state\n", block_id);
700626 goto cleanup;
701627 }
702628
712638 read_buf, sizeof(read_buf));
713639 if (status < 0) {
714640 syslog(LOG_ERR,
715 "NUMA: Failed to read %s valid_zones\n",
716 dir_entry->d_name);
641 "NUMA: Failed to read " MEMBLK_FILE_FMT " valid_zones\n",
642 block_id);
717643 goto cleanup;
718644 }
719645
720646 /* If memory was auto-onlined, check if valid_zones is Movable */
721647 if (strstr(read_buf, VALID_MOVABLE_STATE) != read_buf) {
722648 syslog(LOG_NOTICE, MEMORY_AUTO_ONLINE_WARNING_FMT,
723 dir_entry->d_name, read_buf);
649 block_id, read_buf);
724650 status = -ENOTSUP;
725651 break;
726652 } else {
851777
852778 /* Check if probed memory has been auto-onlined */
853779 status = check_memory_auto_online(numa_info_params.nid,
780 numa_info_params.numa_mem_addr,
781 numa_info_params.numa_mem_size,
782 numa_info_params.memblock_size,
854783 &auto_online_success);
855784 if (status < 0) {
856785 if (status != -ENOTSUP) {
870799 }
871800
872801 status = change_numa_node_state(numa_info_params.nid,
802 numa_info_params.numa_mem_addr,
873803 numa_info_params.numa_mem_size,
874804 numa_info_params.memblock_size,
875805 NV_IOCTL_NUMA_STATUS_ONLINE);
5757 CFLAGS += -Wno-unused-parameter
5858 HOST_CC_ONLY_CFLAGS += -Wno-format-zero-length
5959 HOST_CFLAGS += -Wno-unused-parameter
60
61 # Treat warnings as errors, if requested
62 WARNINGS_AS_ERRORS ?=
63 CFLAGS += $(if $(WARNINGS_AS_ERRORS),-Werror)
6064
6165 DEBUG ?=
6266 DEVELOP ?=
0 NVIDIA_VERSION = 470.74
0 NVIDIA_VERSION = 495.29.05
11
22 # This file.
33 VERSION_MK_FILE := $(lastword $(MAKEFILE_LIST))