get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/51942/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 51942,
    "url": "http://patches.dpdk.org/api/patches/51942/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/2b5404285e5ddc460a857cc90130db1b2c717dfc.1553882085.git.anatoly.burakov@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<2b5404285e5ddc460a857cc90130db1b2c717dfc.1553882085.git.anatoly.burakov@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/2b5404285e5ddc460a857cc90130db1b2c717dfc.1553882085.git.anatoly.burakov@intel.com",
    "date": "2019-03-29T17:55:29",
    "name": "[v2,2/2] memalloc: do not use lockfiles for single file segments mode",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "396f3135f57e5012232ec8b3cd6d3e1f824e5ddc",
    "submitter": {
        "id": 4,
        "url": "http://patches.dpdk.org/api/people/4/?format=api",
        "name": "Anatoly Burakov",
        "email": "anatoly.burakov@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/2b5404285e5ddc460a857cc90130db1b2c717dfc.1553882085.git.anatoly.burakov@intel.com/mbox/",
    "series": [
        {
            "id": 4006,
            "url": "http://patches.dpdk.org/api/series/4006/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=4006",
            "date": "2019-03-29T17:55:28",
            "name": "[v2,1/2] memalloc: refactor segment resizing code",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/4006/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/51942/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/51942/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 84D914CA7;\n\tFri, 29 Mar 2019 18:55:39 +0100 (CET)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby dpdk.org (Postfix) with ESMTP id 983AB4C96\n\tfor <dev@dpdk.org>; Fri, 29 Mar 2019 18:55:33 +0100 (CET)",
            "from orsmga005.jf.intel.com ([10.7.209.41])\n\tby orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t29 Mar 2019 10:55:32 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga005.jf.intel.com with ESMTP; 29 Mar 2019 10:55:30 -0700",
            "from sivswdev05.ir.intel.com (sivswdev05.ir.intel.com\n\t[10.243.17.64])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\tx2THtU8x022596; Fri, 29 Mar 2019 17:55:30 GMT",
            "from sivswdev05.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev05.ir.intel.com with ESMTP id x2THtUQD019440;\n\tFri, 29 Mar 2019 17:55:30 GMT",
            "(from aburakov@localhost)\n\tby sivswdev05.ir.intel.com with LOCAL id x2THtUHX019436;\n\tFri, 29 Mar 2019 17:55:30 GMT"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.60,285,1549958400\"; d=\"scan'208\";a=\"311540287\"",
        "From": "Anatoly Burakov <anatoly.burakov@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "John McNamara <john.mcnamara@intel.com>,\n\tMarko Kovacevic <marko.kovacevic@intel.com>, david.marchand@redhat.com,\n\tthomas@monjalon.net, maxime.coquelin@redhat.com",
        "Date": "Fri, 29 Mar 2019 17:55:29 +0000",
        "Message-Id": "<2b5404285e5ddc460a857cc90130db1b2c717dfc.1553882085.git.anatoly.burakov@intel.com>",
        "X-Mailer": "git-send-email 1.7.0.7",
        "In-Reply-To": [
            "<728c19fa1ed26cdd319fe65e23c4058363dbf2dd.1553882085.git.anatoly.burakov@intel.com>",
            "<07f664c33ddedaa5dcfe82ecb97d931e68b7e33a.1550855529.git.anatoly.burakov@intel.com>"
        ],
        "References": [
            "<728c19fa1ed26cdd319fe65e23c4058363dbf2dd.1553882085.git.anatoly.burakov@intel.com>",
            "<07f664c33ddedaa5dcfe82ecb97d931e68b7e33a.1550855529.git.anatoly.burakov@intel.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH v2 2/2] memalloc: do not use lockfiles for single\n\tfile segments mode",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Due to internal glibc limitations [1], DPDK may exhaust internal\nfile descriptor limits when using smaller page sizes, which results\nin inability to use system calls such as select() by user\napplications.\n\nSingle file segments option stores lock files per page to ensure\nthat pages are deleted when there are no more users, however this\nis not necessary because the processes will be holding onto the\npages anyway because of mmap(). Thus, removing pages from the\nfilesystem is safe even though they may be used by some other\nsecondary process. As a result, single file segments mode no\nlonger stores inordinate amounts of segment fd's, and the above\nissue with fd limits is solved.\n\nHowever, this will not work for legacy mem mode. For that, simply\ndocument that using bigger page sizes is the only option.\n\n[1] https://mails.dpdk.org/archives/dev/2019-February/124386.html\n\nSigned-off-by: Anatoly Burakov <anatoly.burakov@intel.com>\n---\n .../prog_guide/env_abstraction_layer.rst      |  18 ++\n lib/librte_eal/common/eal_filesystem.h        |  11 -\n lib/librte_eal/linux/eal/eal_memalloc.c       | 285 +++++-------------\n 3 files changed, 96 insertions(+), 218 deletions(-)",
    "diff": "diff --git a/doc/guides/prog_guide/env_abstraction_layer.rst b/doc/guides/prog_guide/env_abstraction_layer.rst\nindex 2361c3b8f..faa5f6a0d 100644\n--- a/doc/guides/prog_guide/env_abstraction_layer.rst\n+++ b/doc/guides/prog_guide/env_abstraction_layer.rst\n@@ -214,6 +214,24 @@ Normally, these options do not need to be changed.\n     can later be mapped into that preallocated VA space (if dynamic memory mode\n     is enabled), and can optionally be mapped into it at startup.\n \n++ Segment file descriptors\n+\n+On Linux, in most cases, EAL will store segment file descriptors in EAL. This\n+can become a problem when using smaller page sizes due to underlying limitations\n+of ``glibc`` library. For example, Linux API calls such as ``select()`` may not\n+work correctly because ``glibc`` does not support more than certain number of\n+file descriptors.\n+\n+There are two possible solutions for this problem. The recommended solution is\n+to use ``--single-file-segments`` mode, as that mode will not use a file\n+descriptor per each page, and it will keep compatibility with Virtio with\n+vhost-user backend. This option is not available when using ``--legacy-mem``\n+mode.\n+\n+Another option is to use bigger page sizes. Since fewer pages are required to\n+cover the same memory area, fewer file descriptors will be stored internally\n+by EAL.\n+\n Support for Externally Allocated Memory\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n \ndiff --git a/lib/librte_eal/common/eal_filesystem.h b/lib/librte_eal/common/eal_filesystem.h\nindex 89a3added..f2f83e712 100644\n--- a/lib/librte_eal/common/eal_filesystem.h\n+++ b/lib/librte_eal/common/eal_filesystem.h\n@@ -98,17 +98,6 @@ eal_get_hugefile_path(char *buffer, size_t buflen, const char *hugedir, int f_id\n \treturn buffer;\n }\n \n-/** String format for hugepage map lock files. */\n-#define HUGEFILE_LOCK_FMT \"%s/map_%d.lock\"\n-static inline const char *\n-eal_get_hugefile_lock_path(char *buffer, size_t buflen, int f_id)\n-{\n-\tsnprintf(buffer, buflen, HUGEFILE_LOCK_FMT, rte_eal_get_runtime_dir(),\n-\t\t\tf_id);\n-\tbuffer[buflen - 1] = '\\0';\n-\treturn buffer;\n-}\n-\n /** define the default filename prefix for the %s values above */\n #define HUGEFILE_PREFIX_DEFAULT \"rte\"\n \ndiff --git a/lib/librte_eal/linux/eal/eal_memalloc.c b/lib/librte_eal/linux/eal/eal_memalloc.c\nindex e90fe6c95..4c51fb8ca 100644\n--- a/lib/librte_eal/linux/eal/eal_memalloc.c\n+++ b/lib/librte_eal/linux/eal/eal_memalloc.c\n@@ -83,13 +83,8 @@ static int fallocate_supported = -1; /* unknown */\n /*\n  * we have two modes - single file segments, and file-per-page mode.\n  *\n- * for single-file segments, we need some kind of mechanism to keep track of\n- * which hugepages can be freed back to the system, and which cannot. we cannot\n- * use flock() because they don't allow locking parts of a file, and we cannot\n- * use fcntl() due to issues with their semantics, so we will have to rely on a\n- * bunch of lockfiles for each page. so, we will use 'fds' array to keep track\n- * of per-page lockfiles. we will store the actual segment list fd in the\n- * 'memseg_list_fd' field.\n+ * for single-file segments, we use memseg_list_fd to store the segment fd,\n+ * while the fds[] will not be allocated, and len will be set to 0.\n  *\n  * for file-per-page mode, each page will have its own fd, so 'memseg_list_fd'\n  * will be invalid (set to -1), and we'll use 'fds' to keep track of page fd's.\n@@ -245,80 +240,6 @@ static int lock(int fd, int type)\n \treturn 1;\n }\n \n-static int get_segment_lock_fd(int list_idx, int seg_idx)\n-{\n-\tchar path[PATH_MAX] = {0};\n-\tint fd;\n-\n-\tif (list_idx < 0 || list_idx >= (int)RTE_DIM(fd_list))\n-\t\treturn -1;\n-\tif (seg_idx < 0 || seg_idx >= fd_list[list_idx].len)\n-\t\treturn -1;\n-\n-\tfd = fd_list[list_idx].fds[seg_idx];\n-\t/* does this lock already exist? */\n-\tif (fd >= 0)\n-\t\treturn fd;\n-\n-\teal_get_hugefile_lock_path(path, sizeof(path),\n-\t\t\tlist_idx * RTE_MAX_MEMSEG_PER_LIST + seg_idx);\n-\n-\tfd = open(path, O_CREAT | O_RDWR, 0660);\n-\tif (fd < 0) {\n-\t\tRTE_LOG(ERR, EAL, \"%s(): error creating lockfile '%s': %s\\n\",\n-\t\t\t__func__, path, strerror(errno));\n-\t\treturn -1;\n-\t}\n-\t/* take out a read lock */\n-\tif (lock(fd, LOCK_SH) != 1) {\n-\t\tRTE_LOG(ERR, EAL, \"%s(): failed to take out a readlock on '%s': %s\\n\",\n-\t\t\t__func__, path, strerror(errno));\n-\t\tclose(fd);\n-\t\treturn -1;\n-\t}\n-\t/* store it for future reference */\n-\tfd_list[list_idx].fds[seg_idx] = fd;\n-\tfd_list[list_idx].count++;\n-\treturn fd;\n-}\n-\n-static int unlock_segment(int list_idx, int seg_idx)\n-{\n-\tint fd, ret;\n-\n-\tif (list_idx < 0 || list_idx >= (int)RTE_DIM(fd_list))\n-\t\treturn -1;\n-\tif (seg_idx < 0 || seg_idx >= fd_list[list_idx].len)\n-\t\treturn -1;\n-\n-\tfd = fd_list[list_idx].fds[seg_idx];\n-\n-\t/* upgrade lock to exclusive to see if we can remove the lockfile */\n-\tret = lock(fd, LOCK_EX);\n-\tif (ret == 1) {\n-\t\t/* we've succeeded in taking exclusive lock, this lockfile may\n-\t\t * be removed.\n-\t\t */\n-\t\tchar path[PATH_MAX] = {0};\n-\t\teal_get_hugefile_lock_path(path, sizeof(path),\n-\t\t\t\tlist_idx * RTE_MAX_MEMSEG_PER_LIST + seg_idx);\n-\t\tif (unlink(path)) {\n-\t\t\tRTE_LOG(ERR, EAL, \"%s(): error removing lockfile '%s': %s\\n\",\n-\t\t\t\t\t__func__, path, strerror(errno));\n-\t\t}\n-\t}\n-\t/* we don't want to leak the fd, so even if we fail to lock, close fd\n-\t * and remove it from list anyway.\n-\t */\n-\tclose(fd);\n-\tfd_list[list_idx].fds[seg_idx] = -1;\n-\tfd_list[list_idx].count--;\n-\n-\tif (ret < 0)\n-\t\treturn -1;\n-\treturn 0;\n-}\n-\n static int\n get_seg_memfd(struct hugepage_info *hi __rte_unused,\n \t\tunsigned int list_idx __rte_unused,\n@@ -425,7 +346,7 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,\n }\n \n static int\n-resize_hugefile_in_memory(int fd, int list_idx, uint64_t fa_offset,\n+resize_hugefile_in_memory(int fd, uint64_t fa_offset,\n \t\tuint64_t page_sz, bool grow)\n {\n \tint flags = grow ? 0 : FALLOC_FL_PUNCH_HOLE |\n@@ -441,18 +362,12 @@ resize_hugefile_in_memory(int fd, int list_idx, uint64_t fa_offset,\n \t\t\t\tstrerror(errno));\n \t\treturn -1;\n \t}\n-\t/* increase/decrease total segment count */\n-\tfd_list[list_idx].count += (grow ? 1 : -1);\n-\tif (!grow && fd_list[list_idx].count == 0) {\n-\t\tclose(fd_list[list_idx].memseg_list_fd);\n-\t\tfd_list[list_idx].memseg_list_fd = -1;\n-\t}\n \treturn 0;\n }\n \n static int\n-resize_hugefile_in_filesystem(int fd, char *path, int list_idx, int seg_idx,\n-\t\tuint64_t fa_offset, uint64_t page_sz, bool grow)\n+resize_hugefile_in_filesystem(int fd, uint64_t fa_offset, uint64_t page_sz,\n+\t\tbool grow)\n {\n \tbool again = false;\n \n@@ -481,72 +396,22 @@ resize_hugefile_in_filesystem(int fd, char *path, int list_idx, int seg_idx,\n \t\t} else {\n \t\t\tint flags = grow ? 0 : FALLOC_FL_PUNCH_HOLE |\n \t\t\t\t\tFALLOC_FL_KEEP_SIZE;\n-\t\t\tint ret, lock_fd;\n+\t\t\tint ret;\n \n-\t\t\t/* if fallocate() is supported, we need to take out a\n-\t\t\t * read lock on allocate (to prevent other processes\n-\t\t\t * from deallocating this page), and take out a write\n-\t\t\t * lock on deallocate (to ensure nobody else is using\n-\t\t\t * this page).\n-\t\t\t *\n-\t\t\t * read locks on page itself are already taken out at\n-\t\t\t * file creation, in get_seg_fd().\n-\t\t\t *\n-\t\t\t * we cannot rely on simple use of flock() call, because\n-\t\t\t * we need to be able to lock a section of the file,\n-\t\t\t * and we cannot use fcntl() locks, because of numerous\n-\t\t\t * problems with their semantics, so we will use\n-\t\t\t * deterministically named lock files for each section\n-\t\t\t * of the file.\n-\t\t\t *\n-\t\t\t * if we're shrinking the file, we want to upgrade our\n-\t\t\t * lock from shared to exclusive.\n-\t\t\t *\n-\t\t\t * lock_fd is an fd for a lockfile, not for the segment\n-\t\t\t * list.\n+\t\t\t/*\n+\t\t\t * technically, it is perfectly safe for both primary\n+\t\t\t * and secondary to grow and shrink the page files:\n+\t\t\t * growing the file repeatedly has no effect because\n+\t\t\t * a page can only be allocated once, while mmap ensures\n+\t\t\t * that secondaries hold on to the page even after the\n+\t\t\t * page itself is removed from the filesystem.\n+\t\t\t *\n+\t\t\t * however, leaving growing/shrinking to the primary\n+\t\t\t * tends to expose bugs in fdlist page count handling,\n+\t\t\t * so leave this here just in case.\n \t\t\t */\n-\t\t\tlock_fd = get_segment_lock_fd(list_idx, seg_idx);\n-\n-\t\t\tif (!grow) {\n-\t\t\t\t/* we are using this lockfile to determine\n-\t\t\t\t * whether this particular page is locked, as we\n-\t\t\t\t * are in single file segments mode and thus\n-\t\t\t\t * cannot use regular flock() to get this info.\n-\t\t\t\t *\n-\t\t\t\t * we want to try and take out an exclusive lock\n-\t\t\t\t * on the lock file to determine if we're the\n-\t\t\t\t * last ones using this page, and if not, we\n-\t\t\t\t * won't be shrinking it, and will instead exit\n-\t\t\t\t * prematurely.\n-\t\t\t\t */\n-\t\t\t\tret = lock(lock_fd, LOCK_EX);\n-\n-\t\t\t\t/* drop the lock on the lockfile, so that even\n-\t\t\t\t * if we couldn't shrink the file ourselves, we\n-\t\t\t\t * are signalling to other processes that we're\n-\t\t\t\t * no longer using this page.\n-\t\t\t\t */\n-\t\t\t\tif (unlock_segment(list_idx, seg_idx))\n-\t\t\t\t\tRTE_LOG(ERR, EAL, \"Could not unlock segment\\n\");\n-\n-\t\t\t\t/* additionally, if this was the last lock on\n-\t\t\t\t * this segment list, we can safely close the\n-\t\t\t\t * page file fd, so that one of the processes\n-\t\t\t\t * could then delete the file after shrinking.\n-\t\t\t\t */\n-\t\t\t\tif (ret < 1 && fd_list[list_idx].count == 0) {\n-\t\t\t\t\tclose(fd);\n-\t\t\t\t\tfd_list[list_idx].memseg_list_fd = -1;\n-\t\t\t\t}\n-\n-\t\t\t\tif (ret < 0) {\n-\t\t\t\t\tRTE_LOG(ERR, EAL, \"Could not lock segment\\n\");\n-\t\t\t\t\treturn -1;\n-\t\t\t\t}\n-\t\t\t\tif (ret == 0)\n-\t\t\t\t\t/* failed to lock, not an error. */\n-\t\t\t\t\treturn 0;\n-\t\t\t}\n+\t\t\tif (rte_eal_process_type() != RTE_PROC_PRIMARY)\n+\t\t\t\treturn 0;\n \n \t\t\t/* grow or shrink the file */\n \t\t\tret = fallocate(fd, flags, fa_offset, page_sz);\n@@ -564,44 +429,43 @@ resize_hugefile_in_filesystem(int fd, char *path, int list_idx, int seg_idx,\n \t\t\t\t\t\tstrerror(errno));\n \t\t\t\t\treturn -1;\n \t\t\t\t}\n-\t\t\t} else {\n+\t\t\t} else\n \t\t\t\tfallocate_supported = 1;\n-\n-\t\t\t\t/* we've grew/shrunk the file, and we hold an\n-\t\t\t\t * exclusive lock now. check if there are no\n-\t\t\t\t * more segments active in this segment list,\n-\t\t\t\t * and remove the file if there aren't.\n-\t\t\t\t */\n-\t\t\t\tif (fd_list[list_idx].count == 0) {\n-\t\t\t\t\tif (unlink(path))\n-\t\t\t\t\t\tRTE_LOG(ERR, EAL, \"%s(): unlinking '%s' failed: %s\\n\",\n-\t\t\t\t\t\t\t__func__, path,\n-\t\t\t\t\t\t\tstrerror(errno));\n-\t\t\t\t\tclose(fd);\n-\t\t\t\t\tfd_list[list_idx].memseg_list_fd = -1;\n-\t\t\t\t}\n-\t\t\t}\n \t\t}\n \t} while (again);\n \n \treturn 0;\n }\n \n+static void\n+close_hugefile(int fd, char *path, int list_idx)\n+{\n+\t/*\n+\t * primary process must unlink the file, but only when not in in-memory\n+\t * mode (as in that case there is no file to unlink).\n+\t */\n+\tif (!internal_config.in_memory &&\n+\t\t\trte_eal_process_type() == RTE_PROC_PRIMARY &&\n+\t\t\tunlink(path))\n+\t\tRTE_LOG(ERR, EAL, \"%s(): unlinking '%s' failed: %s\\n\",\n+\t\t\t__func__, path, strerror(errno));\n+\n+\tclose(fd);\n+\tfd_list[list_idx].memseg_list_fd = -1;\n+}\n \n static int\n-resize_hugefile(int fd, char *path, int list_idx, int seg_idx,\n-\t\tuint64_t fa_offset, uint64_t page_sz, bool grow)\n+resize_hugefile(int fd, uint64_t fa_offset, uint64_t page_sz, bool grow)\n {\n-\n-\t/* in-memory mode is a special case, because we don't need to perform\n-\t * any locking, and we can be sure that fallocate() is supported.\n+\t/* in-memory mode is a special case, because we can be sure that\n+\t * fallocate() is supported.\n \t */\n \tif (internal_config.in_memory)\n-\t\treturn resize_hugefile_in_memory(fd, list_idx, fa_offset,\n+\t\treturn resize_hugefile_in_memory(fd, fa_offset,\n \t\t\t\tpage_sz, grow);\n \n-\treturn resize_hugefile_in_filesystem(fd, path, list_idx, seg_idx,\n-\t\t\tfa_offset, page_sz, grow);\n+\treturn resize_hugefile_in_filesystem(fd, fa_offset, page_sz,\n+\t\t\t\tgrow);\n }\n \n static int\n@@ -663,10 +527,11 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,\n \n \t\tif (internal_config.single_file_segments) {\n \t\t\tmap_offset = seg_idx * alloc_sz;\n-\t\t\tret = resize_hugefile(fd, path, list_idx, seg_idx,\n-\t\t\t\t\tmap_offset, alloc_sz, true);\n+\t\t\tret = resize_hugefile(fd, map_offset, alloc_sz, true);\n \t\t\tif (ret < 0)\n \t\t\t\tgoto resized;\n+\n+\t\t\tfd_list[list_idx].count++;\n \t\t} else {\n \t\t\tmap_offset = 0;\n \t\t\tif (ftruncate(fd, alloc_sz) < 0) {\n@@ -769,15 +634,21 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,\n \t\t */\n \t\tRTE_LOG(CRIT, EAL, \"Can't mmap holes in our virtual address space\\n\");\n \t}\n+\t/* roll back the ref count */\n+\tif (internal_config.single_file_segments)\n+\t\tfd_list[list_idx].count--;\n resized:\n \t/* some codepaths will return negative fd, so exit early */\n \tif (fd < 0)\n \t\treturn -1;\n \n \tif (internal_config.single_file_segments) {\n-\t\tresize_hugefile(fd, path, list_idx, seg_idx, map_offset,\n-\t\t\t\talloc_sz, false);\n+\t\tresize_hugefile(fd, map_offset, alloc_sz, false);\n \t\t/* ignore failure, can't make it any worse */\n+\n+\t\t/* if refcount is at zero, close the file */\n+\t\tif (fd_list[list_idx].count == 0)\n+\t\t\tclose_hugefile(fd, path, list_idx);\n \t} else {\n \t\t/* only remove file if we can take out a write lock */\n \t\tif (internal_config.hugepage_unlink == 0 &&\n@@ -834,9 +705,12 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,\n \n \tif (internal_config.single_file_segments) {\n \t\tmap_offset = seg_idx * ms->len;\n-\t\tif (resize_hugefile(fd, path, list_idx, seg_idx, map_offset,\n-\t\t\t\tms->len, false))\n+\t\tif (resize_hugefile(fd, map_offset, ms->len, false))\n \t\t\treturn -1;\n+\n+\t\tif (--(fd_list[list_idx].count) == 0)\n+\t\t\tclose_hugefile(fd, path, list_idx);\n+\n \t\tret = 0;\n \t} else {\n \t\t/* if we're able to take out a write lock, we're the last one\n@@ -1492,18 +1366,24 @@ alloc_list(int list_idx, int len)\n \tint *data;\n \tint i;\n \n-\t/* ensure we have space to store fd per each possible segment */\n-\tdata = malloc(sizeof(int) * len);\n-\tif (data == NULL) {\n-\t\tRTE_LOG(ERR, EAL, \"Unable to allocate space for file descriptors\\n\");\n-\t\treturn -1;\n+\t/* single-file segments mode does not need fd list */\n+\tif (!internal_config.single_file_segments) {\n+\t\t/* ensure we have space to store fd per each possible segment */\n+\t\tdata = malloc(sizeof(int) * len);\n+\t\tif (data == NULL) {\n+\t\t\tRTE_LOG(ERR, EAL, \"Unable to allocate space for file descriptors\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\t/* set all fd's as invalid */\n+\t\tfor (i = 0; i < len; i++)\n+\t\t\tdata[i] = -1;\n+\t\tfd_list[list_idx].fds = data;\n+\t\tfd_list[list_idx].len = len;\n+\t} else {\n+\t\tfd_list[list_idx].fds = NULL;\n+\t\tfd_list[list_idx].len = 0;\n \t}\n-\t/* set all fd's as invalid */\n-\tfor (i = 0; i < len; i++)\n-\t\tdata[i] = -1;\n \n-\tfd_list[list_idx].fds = data;\n-\tfd_list[list_idx].len = len;\n \tfd_list[list_idx].count = 0;\n \tfd_list[list_idx].memseg_list_fd = -1;\n \n@@ -1551,20 +1431,10 @@ eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)\n int\n eal_memalloc_set_seg_list_fd(int list_idx, int fd)\n {\n-\tstruct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;\n-\n \t/* non-single file segment mode doesn't support segment list fd's */\n \tif (!internal_config.single_file_segments)\n \t\treturn -ENOTSUP;\n \n-\t/* if list is not allocated, allocate it */\n-\tif (fd_list[list_idx].len == 0) {\n-\t\tint len = mcfg->memsegs[list_idx].memseg_arr.len;\n-\n-\t\tif (alloc_list(list_idx, len) < 0)\n-\t\t\treturn -ENOMEM;\n-\t}\n-\n \tfd_list[list_idx].memseg_list_fd = fd;\n \n \treturn 0;\n@@ -1642,9 +1512,6 @@ eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset)\n \t\t\treturn -ENOTSUP;\n \t}\n \n-\t/* fd_list not initialized? */\n-\tif (fd_list[list_idx].len == 0)\n-\t\treturn -ENODEV;\n \tif (internal_config.single_file_segments) {\n \t\tsize_t pgsz = mcfg->memsegs[list_idx].page_sz;\n \n@@ -1653,6 +1520,10 @@ eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset)\n \t\t\treturn -ENOENT;\n \t\t*offset = pgsz * seg_idx;\n \t} else {\n+\t\t/* fd_list not initialized? */\n+\t\tif (fd_list[list_idx].len == 0)\n+\t\t\treturn -ENODEV;\n+\n \t\t/* segment not active? */\n \t\tif (fd_list[list_idx].fds[seg_idx] < 0)\n \t\t\treturn -ENOENT;\n",
    "prefixes": [
        "v2",
        "2/2"
    ]
}