diff -pruN 1.43.0-0-2/appveyor.yml 1.44.2-0-1/appveyor.yml
--- 1.43.0-0-2/appveyor.yml	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/appveyor.yml	2022-07-13 06:42:16.000000000 +0000
@@ -1,7 +1,6 @@
 image:
   - Visual Studio 2015
-  - Visual Studio 2017
-  - Visual Studio 2019
+  - Visual Studio 2022
 
 platform:
   - x86
@@ -12,36 +11,21 @@ environment:
     - FROM_DEPS: true
 
     # LuaRocks 3.x
-    - LUA_VER: 5.4.1
+    - LUA_VER: 5.4.4
       NOCOMPAT: true  # with compatibility flags disabled.
-      LUAROCKS_VER: 3.4.0
+      LUAROCKS_VER: 3.8.0
     - LJ_VER: 2.1
-      LUAROCKS_VER: 3.4.0
-
-    # LuaRocks 2.x
-    - LUA_VER: 5.3.2
-      NOCOMPAT: true  # with compatibility flags disabled.
-      LUAROCKS_VER: 2.3.0
-    - LJ_VER: 2.1
-      LUAROCKS_VER: 2.3.0
+      LUAROCKS_VER: 3.8.0
 
 matrix:
   fast_finish: true
   exclude:
     # Skip x86 for LuaRocks tests
     - platform: x86
-      LUAROCKS_VER: 3.4.0
-    - platform: x86
-      LUAROCKS_VER: 2.3.0
-    # Only test LuaRocks with MSVC 2017
-    - image: Visual Studio 2015
-      LUAROCKS_VER: 3.4.0
+      LUAROCKS_VER: 3.8.0
+    # Only test LuaRocks with latest MSVC
     - image: Visual Studio 2015
-      LUAROCKS_VER: 2.3.0
-    - image: Visual Studio 2019
-      LUAROCKS_VER: 3.4.0
-    - image: Visual Studio 2019
-      LUAROCKS_VER: 2.3.0
+      LUAROCKS_VER: 3.8.0
 
 cache:
   - c:\lua -> appveyor.yml
diff -pruN 1.43.0-0-2/.ci/install.bat 1.44.2-0-1/.ci/install.bat
--- 1.43.0-0-2/.ci/install.bat	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/.ci/install.bat	2022-07-13 06:42:16.000000000 +0000
@@ -181,6 +181,7 @@ if not exist "%LR_ROOT%" (
 		set MSVS_GENERATORS[2015]=Visual Studio 14 2015
 		set MSVS_GENERATORS[2017]=Visual Studio 15 2017
 		set MSVS_GENERATORS[2019]=Visual Studio 16 2019
+		set MSVS_GENERATORS[2022]=Visual Studio 17 2022
 
 		set CMAKE_GENERATOR=!MSVS_GENERATORS[%APPVEYOR_BUILD_WORKER_IMAGE:~14,4%]!
 		:: Starting with MSVC 2019, CMake uses -A option to specify arch rather than Win64 suffix
diff -pruN 1.43.0-0-2/.ci/set_compiler_env.bat 1.44.2-0-1/.ci/set_compiler_env.bat
--- 1.43.0-0-2/.ci/set_compiler_env.bat	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/.ci/set_compiler_env.bat	2022-07-13 06:42:16.000000000 +0000
@@ -11,6 +11,10 @@ set arch=x86
 
 if "%platform%" EQU "x64" ( set arch=x86_amd64 )
 
+if "%COMPILER%"=="2022" (
+	set SET_VS_ENV="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat"
+)
+
 if "%COMPILER%"=="2019" (
 	set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat"
 )
diff -pruN 1.43.0-0-2/.ci/setup_lua.sh 1.44.2-0-1/.ci/setup_lua.sh
--- 1.43.0-0-2/.ci/setup_lua.sh	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/.ci/setup_lua.sh	2022-07-13 06:42:16.000000000 +0000
@@ -67,11 +67,11 @@ else
     curl --silent https://www.lua.org/ftp/lua-5.2.4.tar.gz | tar xz
     cd lua-5.2.4;
   elif [ "$LUA" == "lua5.3" ]; then
-    curl --silent https://www.lua.org/ftp/lua-5.3.2.tar.gz | tar xz
-    cd lua-5.3.2;
+    curl --silent https://www.lua.org/ftp/lua-5.3.6.tar.gz | tar xz
+    cd lua-5.3.6;
   elif [ "$LUA" == "lua5.4" ]; then
-    curl --silent https://www.lua.org/ftp/lua-5.4.3.tar.gz | tar xz
-    cd lua-5.4.3;
+    curl --silent https://www.lua.org/ftp/lua-5.4.4.tar.gz | tar xz
+    cd lua-5.4.4;
   fi
 
   # Build Lua without backwards compatibility for testing
@@ -131,7 +131,7 @@ elif [ "$LUA" == "lua5.1" ]; then
 elif [ "$LUA" == "lua5.2" ]; then
   rm -rf lua-5.2.4;
 elif [ "$LUA" == "lua5.3" ]; then
-  rm -rf lua-5.3.2;
+  rm -rf lua-5.3.6;
 elif [ "$LUA" == "lua5.4" ]; then
-  rm -rf lua-5.4.3;
+  rm -rf lua-5.4.4;
 fi
diff -pruN 1.43.0-0-2/CMakeLists.txt 1.44.2-0-1/CMakeLists.txt
--- 1.43.0-0-2/CMakeLists.txt	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/CMakeLists.txt	2022-07-13 06:42:16.000000000 +0000
@@ -7,8 +7,8 @@ endif()
 project (luv C ASM)
 
 set(LUV_VERSION_MAJOR 1)
-set(LUV_VERSION_MINOR 43)
-set(LUV_VERSION_PATCH 0)
+set(LUV_VERSION_MINOR 44)
+set(LUV_VERSION_PATCH 2)
 set(LUV_VERSION ${LUV_VERSION_MAJOR}.${LUV_VERSION_MINOR}.${LUV_VERSION_PATCH})
 
 if(NOT ${CMAKE_VERSION} VERSION_LESS "3.5.0")
@@ -124,7 +124,7 @@ else (LUA)
     if (USE_LUAJIT)
       # We only link the libs on Windows, so find_package fully succeeding
       # is only required on Windows
-      if (WIN32)
+      if (WIN32 OR CYGWIN)
         find_package(LuaJIT REQUIRED)
         link_directories(${LUAJIT_LIBRARIES})
       else()
@@ -137,7 +137,7 @@ else (LUA)
     else (USE_LUAJIT)
       # We only link the libs on Windows, so find_package fully succeeding
       # is only required on Windows
-      if (WIN32)
+      if (WIN32 OR CYGWIN)
         find_package(Lua REQUIRED)
       else()
         find_package(Lua)
@@ -207,18 +207,13 @@ if (BUILD_MODULE)
 endif (BUILD_MODULE)
 if (BUILD_STATIC_LIBS)
   add_library(libluv_a STATIC src/luv.c)
-  set_target_properties(libluv_a PROPERTIES PREFIX "")
+  set_target_properties(libluv_a PROPERTIES OUTPUT_NAME luv)
   list(APPEND ACTIVE_TARGETS "libluv_a")
 endif (BUILD_STATIC_LIBS)
 if (BUILD_SHARED_LIBS)
   add_library(libluv SHARED src/luv.c)
-  set_target_properties(libluv PROPERTIES PREFIX "")
   set_target_properties(libluv
-    PROPERTIES VERSION ${LUV_VERSION} SOVERSION ${LUV_VERSION_MAJOR})
-  # Prevent lib prefix in shared library name
-  if(WIN32)
-    set_target_properties(libluv PROPERTIES IMPORT_PREFIX "")
-  endif(WIN32)
+    PROPERTIES VERSION ${LUV_VERSION} SOVERSION ${LUV_VERSION_MAJOR} OUTPUT_NAME luv)
   if(APPLE)
     set_target_properties(libluv
       PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
@@ -249,7 +244,7 @@ if(WIN32)
 endif()
 
 foreach(TARGET_NAME ${ACTIVE_TARGETS})
-  if(WIN32)
+  if(WIN32 OR CYGWIN)
     if (LUA)
       target_link_libraries(${TARGET_NAME} ${LIBUV_LIBRARIES} ${LUA_LIBRARIES})
     else (LUA)
diff -pruN 1.43.0-0-2/debian/changelog 1.44.2-0-1/debian/changelog
--- 1.43.0-0-2/debian/changelog	2022-02-28 02:02:11.000000000 +0000
+++ 1.44.2-0-1/debian/changelog	2022-08-06 00:44:57.000000000 +0000
@@ -1,3 +1,12 @@
+lua-luv (1.44.2-0-1) unstable; urgency=medium
+
+  * New upstream release
+  * Set Forwarded: not-needed for disable_some_tests.patch
+  * Declare compliance with Policy 4.6.1, no changes needed
+  * Set Lua Team as maintainer, myself as an Uploader
+
+ -- James McCoy <jamessan@debian.org>  Fri, 05 Aug 2022 20:44:57 -0400
+
 lua-luv (1.43.0-0-2) unstable; urgency=medium
 
   * Add allow-stderr restriction for autopkgtests
diff -pruN 1.43.0-0-2/debian/control 1.44.2-0-1/debian/control
--- 1.43.0-0-2/debian/control	2022-02-28 02:02:11.000000000 +0000
+++ 1.44.2-0-1/debian/control	2022-08-06 00:44:57.000000000 +0000
@@ -1,12 +1,14 @@
 Source: lua-luv
 Priority: optional
-Maintainer: Jason Pleau <jason@jpleau.ca>
-Uploaders: James McCoy <jamessan@debian.org>
+Maintainer: Debian Lua Team <pkg-lua-devel@lists.alioth.debian.org>
+Uploaders:
+ Jason Pleau <jason@jpleau.ca>,
+ James McCoy <jamessan@debian.org>,
 Build-Depends: debhelper-compat (= 12),
                dh-lua,
                lua-compat53-dev,
                libuv1-dev,
-Standards-Version: 4.6.0
+Standards-Version: 4.6.1
 Section: interpreters
 Rules-Requires-Root: no
 Homepage: https://github.com/luvit/luv
diff -pruN 1.43.0-0-2/debian/patches/disable_some_tests.patch 1.44.2-0-1/debian/patches/disable_some_tests.patch
--- 1.43.0-0-2/debian/patches/disable_some_tests.patch	2022-02-28 02:02:11.000000000 +0000
+++ 1.44.2-0-1/debian/patches/disable_some_tests.patch	2022-08-06 00:44:57.000000000 +0000
@@ -7,6 +7,7 @@ Description: disable tests that require
  Additionally some tests fail to pass on 32bit architectures with Lua5.1, until
  this is fixed these tests are disabled.
 Author: Jason Pleau <jason@jpleau.ca>
+Forwarded: not-needed
 --- a/tests/run.lua
 +++ b/tests/run.lua
 @@ -18,11 +18,13 @@
diff -pruN 1.43.0-0-2/docs.md 1.44.2-0-1/docs.md
--- 1.43.0-0-2/docs.md	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/docs.md	2022-07-13 06:42:16.000000000 +0000
@@ -2975,14 +2975,14 @@ Copies a file from path to new_path. If
 - `path`: `string`
 - `callback`: `callable` (async version) or `nil` (sync version)
   - `err`: `nil` or `string`
-  - `dir`: `uv_dir_t userdata` or `nil`
+  - `dir`: `luv_dir_t userdata` or `nil`
 - `entries`: `integer` or `nil`
 
 Opens path as a directory stream. Returns a handle that the user can pass to
 `uv.fs_readdir()`. The `entries` parameter defines the maximum number of entries
 that should be returned by each call to `uv.fs_readdir()`.
 
-**Returns (sync version):** `uv_dir_t userdata` or `fail`
+**Returns (sync version):** `luv_dir_t userdata` or `fail`
 
 **Returns (async version):** `uv_fs_t userdata`
 
@@ -2991,12 +2991,12 @@ that should be returned by each call to
 > method form `dir:readdir([callback])`
 
 **Parameters:**
-- `dir`: `uv_dir_t userdata`
+- `dir`: `luv_dir_t userdata`
 - `callback`: `callable` (async version) or `nil` (sync version)
   - `err`: `nil` or `string`
   - `entries`: `table` or `nil` (see below)
 
-Iterates over the directory stream `uv_dir_t` returned by a successful
+Iterates over the directory stream `luv_dir_t` returned by a successful
 `uv.fs_opendir()` call. A table of data tables is returned where the number
 of entries `n` is equal to or less than the `entries` parameter used in
 the associated `uv.fs_opendir()` call.
@@ -3013,7 +3013,7 @@ the associated `uv.fs_opendir()` call.
 > method form `dir:closedir([callback])`
 
 **Parameters:**
-- `dir`: `uv_dir_t userdata`
+- `dir`: `luv_dir_t userdata`
 - `callback`: `callable` (async version) or `nil` (sync version)
   - `err`: `nil` or `string`
   - `success`: `boolean` or `nil`
@@ -3316,6 +3316,18 @@ Returns the resource usage.
 - `nvcsw` : `integer` (voluntary context switches)
 - `nivcsw` : `integer` (involuntary context switches)
 
+### `uv.available_parallelism()`
+
+Returns an estimate of the default amount of parallelism a program should use. Always returns a non-zero value.
+
+On Linux, inspects the calling thread’s CPU affinity mask to determine if it has been pinned to specific CPUs.
+
+On Windows, the available parallelism may be underreported on systems with more than 64 logical CPUs.
+
+On other platforms, reports the number of CPUs that the operating system considers to be online.
+
+**Returns:** `integer`
+
 ### `uv.cpu_info()`
 
 Returns information about the CPU(s) on the system as a table of tables for each
diff -pruN 1.43.0-0-2/.github/workflows/ci.yml 1.44.2-0-1/.github/workflows/ci.yml
--- 1.43.0-0-2/.github/workflows/ci.yml	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/.github/workflows/ci.yml	2022-07-13 06:42:16.000000000 +0000
@@ -45,7 +45,9 @@ jobs:
       with:
         submodules: recursive
     - name: Install Valgrind
-      run: sudo apt-get install -y valgrind
+      run: |
+        sudo apt-get update
+        sudo apt-get install -y valgrind
     - name: Build
       run: make
     - name: Test
@@ -82,17 +84,13 @@ jobs:
     strategy:
       matrix:
         os: [macos-latest, ubuntu-latest]
-        luarocks_version: [2.4.4, 3.7.0]
+        luarocks_version: [3.8.0]
         lua_engine: [Lua, LuaJIT]
         include:
           - lua_engine: LuaJIT
             lua_version: luajit2.1
           - lua_engine: Lua
             lua_version: lua5.4
-          # use 5.3 with Luarocks 2.x
-          - luarocks_version: 2.4.4
-            lua_engine: Lua
-            lua_version: lua5.3
     env:
       # For LuaJIT 2.1, see https://github.com/LuaJIT/LuaJIT/commit/8961a92dd1607108760694af3486b4434602f8be
       MACOSX_DEPLOYMENT_TARGET: 10.12
@@ -139,7 +137,7 @@ jobs:
     env:
       WITH_LUA_ENGINE: LuaJIT
       LUA: luajit2.1
-      LUAROCKS: 3.7.0
+      LUAROCKS: 3.8.0
     steps:
     - uses: actions/checkout@v2
       with:
diff -pruN 1.43.0-0-2/luv-scm-0.rockspec 1.44.2-0-1/luv-scm-0.rockspec
--- 1.43.0-0-2/luv-scm-0.rockspec	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/luv-scm-0.rockspec	2022-07-13 06:42:16.000000000 +0000
@@ -3,11 +3,12 @@ version = "scm-0"
 source = {
   url = 'git://github.com/luvit/luv.git'
 }
+rockspec_format = "3.0"
 
 description = {
   summary = "Bare libuv bindings for lua",
   detailed = [[
-libuv bindings for luajit and lua 5.1/5.2/5.3.
+libuv bindings for luajit and lua 5.1/5.2/5.3/5.4.
 
 This library makes libuv available to lua scripts. It was made for the luvit
 project but should usable from nearly any lua project.
@@ -33,3 +34,8 @@ build = {
      LUADIR="$(LUADIR)",
   },
 }
+
+test = {
+  type = "command",
+  script = "tests/run.lua",
+}
diff -pruN 1.43.0-0-2/msvcbuild.bat 1.44.2-0-1/msvcbuild.bat
--- 1.43.0-0-2/msvcbuild.bat	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/msvcbuild.bat	2022-07-13 06:42:16.000000000 +0000
@@ -1,7 +1,8 @@
 @echo off
 Setlocal EnableDelayedExpansion
 
-if not defined VS set VS=15
+if not defined VS set VS=16
+if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2022" (set VS=17)
 if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2019" (set VS=16)
 if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (set VS=15)
 if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (set VS=14)
diff -pruN 1.43.0-0-2/rockspecs/luv-scm-0.rockspec 1.44.2-0-1/rockspecs/luv-scm-0.rockspec
--- 1.43.0-0-2/rockspecs/luv-scm-0.rockspec	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/rockspecs/luv-scm-0.rockspec	2022-07-13 06:42:16.000000000 +0000
@@ -4,6 +4,7 @@ version = "scm-0"
 source = {
   url = 'git://github.com/luvit/luv.git'
 }
+rockspec_format = "3.0"
 
 description = {
   summary = "Bare libuv bindings for lua",
@@ -84,3 +85,8 @@ build = {
     };
   }
 }
+
+test = {
+  type = "command",
+  script = "tests/run.lua",
+}
diff -pruN 1.43.0-0-2/src/fs.c 1.44.2-0-1/src/fs.c
--- 1.43.0-0-2/src/fs.c	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/src/fs.c	2022-07-13 06:42:16.000000000 +0000
@@ -17,12 +17,30 @@
 
 #include "private.h"
 
+#if LUV_UV_VERSION_GEQ(1, 28, 0)
+typedef struct {
+  uv_dir_t* handle;
+  int dirents_ref; /* handle has been closed if this is LUA_NOREF */
+} luv_dir_t;
+#endif
+
 static uv_fs_t* luv_check_fs(lua_State* L, int index) {
+  if (luaL_testudata(L, index, "uv_fs") != NULL) {
+    return (uv_fs_t*)lua_touserdata(L, index);
+  }
   uv_fs_t* req = (uv_fs_t*)luaL_checkudata(L, index, "uv_req");
   luaL_argcheck(L, req->type == UV_FS && req->data, index, "Expected uv_fs_t");
   return req;
 }
 
+static int luv_fs_gc(lua_State* L) {
+  uv_fs_t* req = luv_check_fs(L, 1);
+  luv_cleanup_req(L, (luv_req_t*)req->data);
+  req->data = NULL;
+  uv_fs_req_cleanup(req);
+  return 0;
+}
+
 static void luv_push_timespec_table(lua_State* L, const uv_timespec_t* t) {
   lua_createtable(L, 0, 2);
   lua_pushinteger(L, t->tv_sec);
@@ -333,14 +351,15 @@ static int push_fs_result(lua_State* L,
       luaL_unref(L, LUA_REGISTRYINDEX, data->data_ref);
       data->data_ref = LUA_NOREF;
 
-      (*(void**)lua_newuserdata(L, sizeof(void*))) = dir;
-      lua_pushfstring(L, "uv_dir:%p", dir);
-      dir->dirents = lua_newuserdata(L, sizeof(uv_dirent_t)*nentries);
-      dir->nentries = nentries;
-      lua_rawset(L, LUA_REGISTRYINDEX);
+      luv_dir_t* luv_dir = lua_newuserdata(L, sizeof(*luv_dir));
       luaL_getmetatable(L, "uv_dir");
       lua_setmetatable(L, -2);
 
+      luv_dir->handle = dir;
+      luv_dir->handle->dirents = lua_newuserdata(L, sizeof(uv_dirent_t)*nentries);
+      luv_dir->dirents_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+      luv_dir->handle->nentries = nentries;
+
       return 1;
     }
     case UV_FS_READDIR: {
@@ -372,6 +391,11 @@ static int push_fs_result(lua_State* L,
 
 static void luv_fs_cb(uv_fs_t* req) {
   luv_req_t* data = (luv_req_t*)req->data;
+  // This can happen if luv_fs_cb is called during loop gc. For example, this can happen
+  // when the async version of fs_scandir is called but the loop is never run before the process exits.
+  //
+  // TODO: A more comprehensive fix for this problem would be related to https://github.com/luvit/luv/issues/437
+  if (data == NULL) return;
   lua_State* L = data->ctx->L;
 
   int nargs = push_fs_result(L, req);
@@ -430,9 +454,11 @@ static void luv_fs_cb(uv_fs_t* req) {
           uv_strerror(req->result));                      \
     }                                                     \
     lua_pushstring(L, uv_err_name(req->result));          \
-    luv_cleanup_req(L, data);                             \
-    req->data = NULL;                                     \
-    uv_fs_req_cleanup(req);                               \
+    if(req->fs_type != UV_FS_SCANDIR) {                   \
+      luv_cleanup_req(L, data);                           \
+      req->data = NULL;                                   \
+      uv_fs_req_cleanup(req);                             \
+    }                                                     \
     nargs = 3;                                            \
   }                                                       \
   else if (sync) {                                        \
@@ -581,7 +607,7 @@ static int luv_fs_scandir(lua_State* L)
   int flags = 0; // TODO: find out what these flags are.
   int ref = luv_check_continuation(L, 2);
   uv_fs_t* req = (uv_fs_t*)lua_newuserdata(L, uv_req_size(UV_FS));
-  req->data = luv_setup_req(L, ctx, ref);
+  req->data = luv_setup_req_with_mt(L, ctx, ref, "uv_fs");
   FS_CALL(scandir, req, path, flags);
 }
 
@@ -589,12 +615,7 @@ static int luv_fs_scandir_next(lua_State
   uv_fs_t* req = luv_check_fs(L, 1);
   uv_dirent_t ent;
   int ret = uv_fs_scandir_next(req, &ent);
-  if (ret == UV_EOF) {
-    luv_cleanup_req(L, (luv_req_t*)req->data);
-    req->data = NULL;
-    uv_fs_req_cleanup(req);
-    return 0;
-  }
+  if (ret == UV_EOF) return 0;
   if (ret < 0) return luv_error(L, ret);
   return luv_push_dirent(L, &ent, 0);
 }
@@ -888,8 +909,8 @@ static int luv_fs_copyfile(lua_State*L)
 #endif
 
 #if LUV_UV_VERSION_GEQ(1, 28, 0)
-static uv_dir_t* luv_check_dir(lua_State* L, int idx) {
-  uv_dir_t* dir = *(uv_dir_t**)luaL_checkudata(L, idx, "uv_dir");
+static luv_dir_t* luv_check_dir(lua_State* L, int idx) {
+  luv_dir_t* dir = (luv_dir_t*)luaL_checkudata(L, idx, "uv_dir");
   return dir;
 }
 
@@ -911,45 +932,44 @@ static int luv_fs_opendir(lua_State* L)
 static int luv_fs_readdir(lua_State* L) {
   luv_ctx_t* ctx = luv_context(L);
   uv_fs_t *req;
-  uv_dir_t* dir = luv_check_dir(L, 1);
+  luv_dir_t* dir = luv_check_dir(L, 1);
   int ref = luv_check_continuation(L, 2);
 
   req = (uv_fs_t*)lua_newuserdata(L, uv_req_size(UV_FS));
   req->data = luv_setup_req(L, ctx, ref);
-  FS_CALL(readdir, req, dir);
+  FS_CALL(readdir, req, dir->handle);
 }
 
 static int luv_fs_closedir(lua_State* L) {
   luv_ctx_t* ctx = luv_context(L);
-  uv_dir_t* dir = luv_check_dir(L, 1);
+  luv_dir_t* dir = luv_check_dir(L, 1);
   int ref = luv_check_continuation(L, 2);
+
+  luaL_unref(L, LUA_REGISTRYINDEX, dir->dirents_ref);
+  dir->dirents_ref = LUA_NOREF;
+
   uv_fs_t *req = (uv_fs_t*)lua_newuserdata(L, uv_req_size(UV_FS));
   req->data = luv_setup_req(L, ctx, ref);
-  lua_pushfstring(L, "uv_dir:%p", dir);
-  lua_pushnil(L);
-  lua_rawset(L, LUA_REGISTRYINDEX);
-  FS_CALL(closedir, req, dir);
+  FS_CALL(closedir, req, dir->handle);
 }
 
 static int luv_fs_dir_tostring(lua_State* L) {
-  uv_dir_t* dir = luv_check_dir(L, 1);
+  luv_dir_t* dir = luv_check_dir(L, 1);
   lua_pushfstring(L, "uv_dir_t: %p", dir);
   return 1;
 }
 
 static int luv_fs_dir_gc(lua_State* L) {
-  uv_dir_t* dir = luv_check_dir(L, 1);
-  lua_pushfstring(L, "uv_dir:%p", dir);
-  lua_rawget(L, LUA_REGISTRYINDEX);
-  if (!lua_isnil(L, -1)) {
+  luv_dir_t* dir = luv_check_dir(L, 1);
+  if (dir->dirents_ref != LUA_NOREF) {
     uv_fs_t req;
     luv_ctx_t* ctx = luv_context(L);
 
-    uv_fs_closedir(ctx->loop, &req, dir, NULL);
+    luaL_unref(L, LUA_REGISTRYINDEX, dir->dirents_ref);
+    dir->dirents_ref = LUA_NOREF;
+
+    uv_fs_closedir(ctx->loop, &req, dir->handle, NULL);
     uv_fs_req_cleanup(&req);
-    lua_pushfstring(L, "uv_dir:%p", dir);
-    lua_pushnil(L);
-    lua_rawset(L, LUA_REGISTRYINDEX);
   }
   lua_pop(L, 1);
 
diff -pruN 1.43.0-0-2/src/handle.c 1.44.2-0-1/src/handle.c
--- 1.43.0-0-2/src/handle.c	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/src/handle.c	2022-07-13 06:42:16.000000000 +0000
@@ -35,6 +35,15 @@ static uv_handle_t* luv_check_handle(lua
   if (!(udata = lua_touserdata(L, index))) { goto fail; }
   if (!(handle = *(uv_handle_t**) udata)) { goto fail; }
   if (!handle->data) { goto fail; }
+  // "uv_handle" in the registry is a table structured like so:
+  // {
+  //   [<uv_aync metatable>] = true,
+  //   [<uv_check metatable>] = true,
+  //   ...
+  // }
+  // so to check that the value at the index is a "uv_handle",
+  // we get its metatable and check that we get `true` back
+  // when looking the metatable up in the "uv_handle" table.
   lua_getfield(L, LUA_REGISTRYINDEX, "uv_handle");
   lua_getmetatable(L, index < 0 ? index - 1 : index);
   lua_rawget(L, -2);
diff -pruN 1.43.0-0-2/src/lreq.c 1.44.2-0-1/src/lreq.c
--- 1.43.0-0-2/src/lreq.c	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/src/lreq.c	2022-07-13 06:42:16.000000000 +0000
@@ -26,7 +26,7 @@ static int luv_check_continuation(lua_St
 
 // Store a lua callback in a luv_req for the continuation.
 // The uv_req_t is assumed to be at the top of the stack
-static luv_req_t* luv_setup_req(lua_State* L, luv_ctx_t* ctx, int cb_ref) {
+static luv_req_t* luv_setup_req_with_mt(lua_State* L, luv_ctx_t* ctx, int cb_ref, const char* mt_name) {
   luv_req_t* data;
 
   luaL_checktype(L, -1, LUA_TUSERDATA);
@@ -34,7 +34,7 @@ static luv_req_t* luv_setup_req(lua_Stat
   data = (luv_req_t*)malloc(sizeof(*data));
   if (!data) luaL_error(L, "Problem allocating luv request");
 
-  luaL_getmetatable(L, "uv_req");
+  luaL_getmetatable(L, mt_name);
   lua_setmetatable(L, -2);
 
   lua_pushvalue(L, -1);
@@ -47,6 +47,10 @@ static luv_req_t* luv_setup_req(lua_Stat
   return data;
 }
 
+static luv_req_t* luv_setup_req(lua_State* L, luv_ctx_t* ctx, int cb_ref) {
+  return luv_setup_req_with_mt(L, ctx, cb_ref, "uv_req");
+}
+
 
 static void luv_fulfill_req(lua_State* L, luv_req_t* data, int nargs) {
   if (data->callback_ref == LUA_NOREF) {
diff -pruN 1.43.0-0-2/src/luv.c 1.44.2-0-1/src/luv.c
--- 1.43.0-0-2/src/luv.c	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/src/luv.c	2022-07-13 06:42:16.000000000 +0000
@@ -306,6 +306,9 @@ static const luaL_Reg luv_functions[] =
   {"os_tmpdir", luv_os_tmpdir},
   {"os_get_passwd", luv_os_get_passwd},
 #endif
+#if LUV_UV_VERSION_GEQ(1, 44, 0)
+  {"available_parallelism", luv_available_parallelism},
+#endif
   {"cpu_info", luv_cpu_info},
   {"cwd", luv_cwd},
   {"exepath", luv_exepath},
@@ -645,6 +648,17 @@ static void luv_req_init(lua_State* L) {
   luaL_newlib(L, luv_req_methods);
   lua_setfield(L, -2, "__index");
   lua_pop(L, 1);
+
+  // Only used for things that need to be garbage collected
+  // (e.g. the req when using uv_fs_scandir)
+  luaL_newmetatable(L, "uv_fs");
+  lua_pushcfunction(L, luv_req_tostring);
+  lua_setfield(L, -2, "__tostring");
+  luaL_newlib(L, luv_req_methods);
+  lua_setfield(L, -2, "__index");
+  lua_pushcfunction(L, luv_fs_gc);
+  lua_setfield(L, -2, "__gc");
+  lua_pop(L, 1);
 }
 
 // Call lua function, will pop nargs values from top of vm stack and push some
diff -pruN 1.43.0-0-2/src/misc.c 1.44.2-0-1/src/misc.c
--- 1.43.0-0-2/src/misc.c	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/src/misc.c	2022-07-13 06:42:16.000000000 +0000
@@ -221,6 +221,13 @@ static int luv_getrusage(lua_State* L) {
   return 1;
 }
 
+#if LUV_UV_VERSION_GEQ(1, 44, 0)
+static int luv_available_parallelism(lua_State* L) {
+  lua_pushinteger(L, uv_available_parallelism());
+  return 1;
+}
+#endif
+
 static int luv_cpu_info(lua_State* L) {
   uv_cpu_info_t* cpu_infos = NULL;
   int count = 0, i;
@@ -366,14 +373,15 @@ static int luv_os_get_passwd(lua_State*
     lua_pushstring(L, pwd.username);
     lua_setfield(L, -2, "username");
   }
-  if (pwd.uid >= 0) {
-    lua_pushinteger(L, pwd.uid);
-    lua_setfield(L, -2, "uid");
-  }
-  if (pwd.gid >= 0) {
-    lua_pushinteger(L, pwd.gid);
-    lua_setfield(L, -2, "gid");
-  }
+  // From the uv_os_get_passwd docs:
+  // "On Windows, uid and gid are set to -1 and have no meaning"
+  // so we omit these fields on Windows.
+#ifndef _WIN32
+  lua_pushinteger(L, pwd.uid);
+  lua_setfield(L, -2, "uid");
+  lua_pushinteger(L, pwd.gid);
+  lua_setfield(L, -2, "gid");
+#endif
   if (pwd.shell) {
     lua_pushstring(L, pwd.shell);
     lua_setfield(L, -2, "shell");
diff -pruN 1.43.0-0-2/src/private.h 1.44.2-0-1/src/private.h
--- 1.43.0-0-2/src/private.h	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/src/private.h	2022-07-13 06:42:16.000000000 +0000
@@ -54,6 +54,7 @@ static int luv_check_continuation(lua_St
    top of the stack.
 */
 static luv_req_t* luv_setup_req(lua_State* L, luv_ctx_t* ctx, int ref);
+static luv_req_t* luv_setup_req_with_mt(lua_State* L, luv_ctx_t* ctx, int ref, const char* mt_name);
 static void luv_fulfill_req(lua_State* L, luv_req_t* data, int nargs);
 static void luv_cleanup_req(lua_State* L, luv_req_t* data);
 
diff -pruN 1.43.0-0-2/src/req.c 1.44.2-0-1/src/req.c
--- 1.43.0-0-2/src/req.c	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/src/req.c	2022-07-13 06:42:16.000000000 +0000
@@ -17,13 +17,16 @@
 #include "private.h"
 
 static uv_req_t* luv_check_req(lua_State* L, int index) {
+  if (luaL_testudata(L, index, "uv_fs") != NULL) {
+    return (uv_req_t*)lua_touserdata(L, index);
+  }
   uv_req_t* req = (uv_req_t*)luaL_checkudata(L, index, "uv_req");
   luaL_argcheck(L, req->data, index, "Expected uv_req_t");
   return req;
 }
 
 static int luv_req_tostring(lua_State* L) {
-  uv_req_t* req = (uv_req_t*)luaL_checkudata(L, 1, "uv_req");
+  uv_req_t* req = luv_check_req(L, 1);
   switch (req->type) {
 #define XX(uc, lc) case UV_##uc: lua_pushfstring(L, "uv_"#lc"_t: %p", req); break;
   UV_REQ_TYPE_MAP(XX)
diff -pruN 1.43.0-0-2/src/stream.c 1.44.2-0-1/src/stream.c
--- 1.43.0-0-2/src/stream.c	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/src/stream.c	2022-07-13 06:42:16.000000000 +0000
@@ -23,6 +23,15 @@ static uv_stream_t* luv_check_stream(lua
   if (!(udata = lua_touserdata(L, index))) { goto fail; }
   if (!(handle = *(uv_stream_t**) udata)) { goto fail; }
   if (!handle->data) { goto fail; }
+  // "uv_stream" in the registry is a table structured like so:
+  // {
+  //   [<uv_pipe metatable>] = true,
+  //   [<uv_tcp metatable>] = true,
+  //   [<uv_tty metatable>] = true,
+  // }
+  // so to check that the value at the index is a "uv_stream",
+  // we get its metatable and check that we get `true` back
+  // when looking the metatable up in the "uv_stream" table.
   lua_getfield(L, LUA_REGISTRYINDEX, "uv_stream");
   lua_getmetatable(L, index < 0 ? index - 1 : index);
   lua_rawget(L, -2);
diff -pruN 1.43.0-0-2/src/thread.c 1.44.2-0-1/src/thread.c
--- 1.43.0-0-2/src/thread.c	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/src/thread.c	2022-07-13 06:42:16.000000000 +0000
@@ -214,23 +214,11 @@ static int luv_thread_arg_error(lua_Stat
     lua_typename(L, type), pos);
 }
 
-// Copied from lstrlib.c in Lua 5.4.3
-//
-// luaL_buffinit might push stuff onto the stack (this is undocumented as of now),
-// so it must be called after lua_dump to ensure that the function to dump
-// is still on the top of the stack
-struct luv_thread_Writer {
-  int init;
-  luaL_Buffer B;
-};
-
 static int thread_dump (lua_State *L, const void *b, size_t size, void *ud) {
-  struct luv_thread_Writer *state = (struct luv_thread_Writer *)ud;
-  if (!state->init) {
-    state->init = 1;
-    luaL_buffinit(L, &state->B);
-  }
-  luaL_addlstring(&state->B, (const char *)b, size);
+  luaL_Buffer *B = (luaL_Buffer *)ud;
+  (void)L;
+
+  luaL_addlstring(B, (const char *)b, size);
   return 0;
 }
 
@@ -238,15 +226,19 @@ static int luv_thread_dumped(lua_State*
   if (lua_isstring(L, idx)) {
     lua_pushvalue(L, idx);
   } else {
-    int ret;
-    struct luv_thread_Writer state;
-    state.init = 0;
+    int ret, top;
+    luaL_Buffer B;
+
+    // In Lua >= 5.4.3, luaL_buffinit pushes a value onto the stack, so it needs to be called
+    // here to ensure that the function is at the top of the stack during the lua_dump call
+    luaL_buffinit(L, &B);
     luaL_checktype(L, idx, LUA_TFUNCTION);
     lua_pushvalue(L, idx);
-    ret = lua_dump(L, thread_dump, &state, 1);
-    lua_pop(L, 1);
+    top = lua_gettop(L);
+    ret = lua_dump(L, thread_dump, &B, 1);
+    lua_remove(L, top);
     if (ret==0) {
-      luaL_pushresult(&state.B);
+      luaL_pushresult(&B);
     } else
       luaL_error(L, "Error: unable to dump given function");
   }
diff -pruN 1.43.0-0-2/tests/test-fs.lua 1.44.2-0-1/tests/test-fs.lua
--- 1.43.0-0-2/tests/test-fs.lua	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/tests/test-fs.lua	2022-07-13 06:42:16.000000000 +0000
@@ -125,6 +125,52 @@ return require('lib/tap')(function (test
     end
   end)
 
+  test("fs.scandir sync error", function (print, p, expect, uv)
+    local req, err, code = uv.fs_scandir('BAD_FILE!')
+    p{err=err,code=code,req=req}
+    assert(not req)
+    assert(err)
+    assert(code == "ENOENT")
+  end)
+
+  test("fs.scandir async error", function (print, p, expect, uv)
+    local _req, _err = uv.fs_scandir('BAD_FILE!', expect(function(err, req)
+      p{err=err,req=req}
+      assert(not req)
+      assert(err)
+    end))
+    -- Note: when using the async version, the initial return only errors
+    -- if there is an error when setting up the internal Libuv call
+    -- (e.g. if there's an out-of-memory error when copying the path).
+    -- So even though the callback will have an error, the initial call
+    -- should return a valid uv_fs_t userdata without an error.
+    assert(_req)
+    assert(not _err)
+  end)
+
+  test("fs.scandir async", function (print, p, expect, uv)
+    assert(uv.fs_scandir('.', function(err, req)
+      assert(not err)
+      local function iter()
+        return uv.fs_scandir_next(req)
+      end
+      for name, ftype in iter do
+        p{name=name, ftype=ftype}
+        assert(name)
+        -- ftype is not available in all filesystems; for example it's
+        -- provided for HFS+ (OSX), NTFS (Windows) but not for ext4 (Linux).
+      end
+    end))
+  end)
+
+  -- this test does nothing on its own, but when run with a leak checker,
+  -- it will check that the memory allocated by Libuv for req is cleaned up
+  -- even if its not iterated fully (or at all)
+  test("fs.scandir with no iteration", function(print, p, expect, uv)
+    local req = uv.fs_scandir('.')
+    assert(req)
+  end)
+
   test("fs.realpath", function (print, p, expect, uv)
     p(assert(uv.fs_realpath('.')))
     assert(uv.fs_realpath('.', expect(function (err, path)
@@ -212,6 +258,17 @@ return require('lib/tap')(function (test
     assert(uv.fs_opendir('.', opendir_cb, 50))
   end, "1.28.0")
 
+  test("fs.opendir and fs.closedir in a loop", function(print, p, expect, uv)
+    -- Previously, this triggered a GC/closedir race condition
+    -- see https://github.com/luvit/luv/issues/597
+    for _ = 1,1000 do
+      local dir, err = uv.fs_opendir('.', nil, 64)
+      if not err then
+        uv.fs_closedir(dir)
+      end
+    end
+  end, "1.28.0")
+
   test("fs.statfs sync", function (print, p, expect, uv)
     local stat = assert(uv.fs_statfs("."))
     p(stat)
diff -pruN 1.43.0-0-2/tests/test-misc.lua 1.44.2-0-1/tests/test-misc.lua
--- 1.43.0-0-2/tests/test-misc.lua	2022-01-28 13:02:03.000000000 +0000
+++ 1.44.2-0-1/tests/test-misc.lua	2022-07-13 06:42:16.000000000 +0000
@@ -39,6 +39,11 @@ return require('lib/tap')(function (test
     p(rusage)
   end)
 
+  test("uv.available_parallelism", function (print, p, expect, uv)
+    local available_parallelism = assert(uv.available_parallelism())
+    p(available_parallelism)
+  end, "1.44.0")
+
   test("uv.cpu_info", function (print, p, expect, uv)
     local info = assert(uv.cpu_info())
     p(info)
