Add a test
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index f676454..76f4556 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -205,6 +205,12 @@
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
+void on_fd_released(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+  int *done = arg;
+  *done = 1;
+  grpc_pollset_kick(&g_pollset, NULL);
+}
+
 /* Write to a socket until it fills up, then read from it using the grpc_tcp
    API. */
 static void large_read_test(size_t slice_size) {
@@ -383,6 +389,71 @@
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
+/* Do a read_test, then release fd and try to read/write again. */
+static void release_fd_test(size_t num_bytes, size_t slice_size) {
+  int sv[2];
+  grpc_endpoint *ep;
+  struct read_socket_state state;
+  size_t written_bytes;
+  int fd;
+  gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(20);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_closure fd_released_cb;
+  int fd_released_done = 0;
+  grpc_closure_init(&fd_released_cb, &on_fd_released, &fd_released_done);
+
+  gpr_log(GPR_INFO, "Release fd read_test of size %d, slice size %d", num_bytes,
+          slice_size);
+
+  create_sockets(sv);
+
+  ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), slice_size, "test");
+  fd = grpc_tcp_get_fd(ep);
+  GPR_ASSERT(fd == sv[1]);
+  grpc_endpoint_add_to_pollset(&exec_ctx, ep, &g_pollset);
+
+  written_bytes = fill_socket_partial(sv[0], num_bytes);
+  gpr_log(GPR_INFO, "Wrote %d bytes", written_bytes);
+
+  state.ep = ep;
+  state.read_bytes = 0;
+  state.target_read_bytes = written_bytes;
+  gpr_slice_buffer_init(&state.incoming);
+  grpc_closure_init(&state.read_cb, read_cb, &state);
+
+  grpc_endpoint_read(&exec_ctx, ep, &state.incoming, &state.read_cb);
+
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  while (state.read_bytes < state.target_read_bytes) {
+    grpc_pollset_worker worker;
+    grpc_pollset_work(&exec_ctx, &g_pollset, &worker,
+                      gpr_now(GPR_CLOCK_MONOTONIC), deadline);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_exec_ctx_finish(&exec_ctx);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  }
+  GPR_ASSERT(state.read_bytes == state.target_read_bytes);
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+
+  gpr_slice_buffer_destroy(&state.incoming);
+  grpc_tcp_destroy_and_release_fd(&exec_ctx, ep, &fd_released_cb);
+  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  while (!fd_released_done) {
+    grpc_pollset_worker worker;
+    grpc_pollset_work(&exec_ctx, &g_pollset, &worker,
+                      gpr_now(GPR_CLOCK_MONOTONIC), deadline);
+  }
+  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+  GPR_ASSERT(fd_released_done == 1);
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  written_bytes = fill_socket_partial(sv[0], num_bytes);
+  drain_socket_blocking(fd, written_bytes, written_bytes);
+  written_bytes = fill_socket_partial(fd, num_bytes);
+  drain_socket_blocking(sv[0], written_bytes, written_bytes);
+  close(fd);
+}
+
 void run_tests(void) {
   size_t i = 0;
 
@@ -402,6 +473,8 @@
   for (i = 1; i < 1000; i = GPR_MAX(i + 1, i * 5 / 4)) {
     write_test(40320, i);
   }
+
+  release_fd_test(100, 8192);
 }
 
 static void clean_up(void) {}