Skip to content

Commit 2bf7827

Browse files
ronkorvingsaghul
authored andcommitted
unix: allow nbufs > IOV_MAX in uv_fs_{read,write}
This allows writing and reading any amount of buffers, regardless of what IOV_MAX may be defined as. It also moves the IOV_MAX test from stream to core. This is based on the excellent work of @bwijen in #269. Refs: #269 PR-URL: #448 Reviewed-By: Saúl Ibarra Corretgé <[email protected]>
1 parent 0b4f488 commit 2bf7827

6 files changed

Lines changed: 248 additions & 21 deletions

File tree

src/unix/core.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
#include <sys/un.h>
3636
#include <netinet/in.h>
3737
#include <arpa/inet.h>
38-
#include <limits.h> /* INT_MAX, PATH_MAX */
38+
#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
3939
#include <sys/uio.h> /* writev */
4040
#include <sys/resource.h> /* getrusage */
4141
#include <pwd.h>
@@ -199,6 +199,19 @@ void uv__make_close_pending(uv_handle_t* handle) {
199199
handle->loop->closing_handles = handle;
200200
}
201201

202+
int uv__getiovmax(void) {
203+
#if defined(IOV_MAX)
204+
return IOV_MAX;
205+
#elif defined(_SC_IOV_MAX)
206+
static int iovmax = -1;
207+
if (iovmax == -1)
208+
iovmax = sysconf(_SC_IOV_MAX);
209+
return iovmax;
210+
#else
211+
return 1024;
212+
#endif
213+
}
214+
202215

203216
static void uv__finish_close(uv_handle_t* handle) {
204217
/* Note: while the handle is in the UV_CLOSING state now, it's still possible

src/unix/fs.c

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,6 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
309309
}
310310

311311
done:
312-
if (req->bufs != req->bufsml)
313-
uv__free(req->bufs);
314312
return result;
315313
}
316314

@@ -670,9 +668,6 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
670668
pthread_mutex_unlock(&lock);
671669
#endif
672670

673-
if (req->bufs != req->bufsml)
674-
uv__free(req->bufs);
675-
676671
return r;
677672
}
678673

@@ -777,6 +772,47 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
777772
}
778773

779774

775+
typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
776+
static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
777+
unsigned int iovmax;
778+
unsigned int nbufs;
779+
uv_buf_t* bufs;
780+
ssize_t total;
781+
ssize_t result;
782+
783+
iovmax = uv__getiovmax();
784+
nbufs = req->nbufs;
785+
bufs = req->bufs;
786+
total = 0;
787+
788+
while (nbufs > 0) {
789+
req->nbufs = nbufs;
790+
if (req->nbufs > iovmax)
791+
req->nbufs = iovmax;
792+
793+
result = process(req);
794+
if (result <= 0) {
795+
if (total == 0)
796+
total = result;
797+
break;
798+
}
799+
800+
if (req->off >= 0)
801+
req->off += result;
802+
803+
req->bufs += req->nbufs;
804+
nbufs -= req->nbufs;
805+
total += result;
806+
}
807+
808+
if (bufs != req->bufsml)
809+
uv__free(bufs);
810+
req->bufs = NULL;
811+
812+
return total;
813+
}
814+
815+
780816
static void uv__fs_work(struct uv__work* w) {
781817
int retry_on_eintr;
782818
uv_fs_t* req;
@@ -810,7 +846,7 @@ static void uv__fs_work(struct uv__work* w) {
810846
X(MKDIR, mkdir(req->path, req->mode));
811847
X(MKDTEMP, uv__fs_mkdtemp(req));
812848
X(OPEN, uv__fs_open(req));
813-
X(READ, uv__fs_read(req));
849+
X(READ, uv__fs_buf_iter(req, uv__fs_read));
814850
X(SCANDIR, uv__fs_scandir(req));
815851
X(READLINK, uv__fs_readlink(req));
816852
X(RENAME, rename(req->path, req->new_path));
@@ -820,7 +856,7 @@ static void uv__fs_work(struct uv__work* w) {
820856
X(SYMLINK, symlink(req->path, req->new_path));
821857
X(UNLINK, unlink(req->path));
822858
X(UTIME, uv__fs_utime(req));
823-
X(WRITE, uv__fs_write(req));
859+
X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
824860
default: abort();
825861
}
826862
#undef X

src/unix/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ int uv__socket(int domain, int type, int protocol);
178178
int uv__dup(int fd);
179179
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
180180
void uv__make_close_pending(uv_handle_t* handle);
181+
int uv__getiovmax(void);
181182

182183
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
183184
void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);

src/unix/stream.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -739,19 +739,6 @@ static int uv__handle_fd(uv_handle_t* handle) {
739739
}
740740
}
741741

742-
static int uv__getiovmax() {
743-
#if defined(IOV_MAX)
744-
return IOV_MAX;
745-
#elif defined(_SC_IOV_MAX)
746-
static int iovmax = -1;
747-
if (iovmax == -1)
748-
iovmax = sysconf(_SC_IOV_MAX);
749-
return iovmax;
750-
#else
751-
return 1024;
752-
#endif
753-
}
754-
755742
static void uv__write(uv_stream_t* stream) {
756743
struct iovec* iov;
757744
QUEUE* q;

test/test-fs.c

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2328,3 +2328,189 @@ TEST_IMPL(fs_write_multiple_bufs) {
23282328
MAKE_VALGRIND_HAPPY();
23292329
return 0;
23302330
}
2331+
2332+
2333+
TEST_IMPL(fs_write_alotof_bufs) {
2334+
const size_t iovcount = 54321;
2335+
uv_buf_t* iovs;
2336+
char* buffer;
2337+
size_t index;
2338+
int r;
2339+
2340+
/* Setup. */
2341+
unlink("test_file");
2342+
2343+
loop = uv_default_loop();
2344+
2345+
iovs = malloc(sizeof(*iovs) * iovcount);
2346+
ASSERT(iovs != NULL);
2347+
2348+
r = uv_fs_open(loop,
2349+
&open_req1,
2350+
"test_file",
2351+
O_RDWR | O_CREAT,
2352+
S_IWUSR | S_IRUSR,
2353+
NULL);
2354+
ASSERT(r >= 0);
2355+
ASSERT(open_req1.result >= 0);
2356+
uv_fs_req_cleanup(&open_req1);
2357+
2358+
for (index = 0; index < iovcount; ++index)
2359+
iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
2360+
2361+
r = uv_fs_write(loop,
2362+
&write_req,
2363+
open_req1.result,
2364+
iovs,
2365+
iovcount,
2366+
-1,
2367+
NULL);
2368+
ASSERT(r >= 0);
2369+
ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
2370+
uv_fs_req_cleanup(&write_req);
2371+
2372+
/* Read the strings back to separate buffers. */
2373+
buffer = malloc(sizeof(test_buf) * iovcount);
2374+
ASSERT(buffer != NULL);
2375+
2376+
for (index = 0; index < iovcount; ++index)
2377+
iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
2378+
sizeof(test_buf));
2379+
2380+
r = uv_fs_read(loop, &read_req, open_req1.result, iovs, iovcount, 0, NULL);
2381+
ASSERT(r >= 0);
2382+
ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount);
2383+
2384+
for (index = 0; index < iovcount; ++index)
2385+
ASSERT(strncmp(buffer + index * sizeof(test_buf),
2386+
test_buf,
2387+
sizeof(test_buf)) == 0);
2388+
2389+
uv_fs_req_cleanup(&read_req);
2390+
free(buffer);
2391+
2392+
iov = uv_buf_init(buf, sizeof(buf));
2393+
r = uv_fs_read(loop,
2394+
&read_req,
2395+
open_req1.result,
2396+
&iov,
2397+
1,
2398+
read_req.result,
2399+
NULL);
2400+
ASSERT(r == 0);
2401+
ASSERT(read_req.result == 0);
2402+
uv_fs_req_cleanup(&read_req);
2403+
2404+
r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
2405+
ASSERT(r == 0);
2406+
ASSERT(close_req.result == 0);
2407+
uv_fs_req_cleanup(&close_req);
2408+
2409+
/* Cleanup */
2410+
unlink("test_file");
2411+
free(iovs);
2412+
2413+
MAKE_VALGRIND_HAPPY();
2414+
return 0;
2415+
}
2416+
2417+
2418+
TEST_IMPL(fs_write_alotof_bufs_with_offset) {
2419+
const size_t iovcount = 54321;
2420+
uv_buf_t* iovs;
2421+
char* buffer;
2422+
size_t index;
2423+
int r;
2424+
int64_t offset;
2425+
char* filler = "0123456789";
2426+
int filler_len = strlen(filler);
2427+
2428+
/* Setup. */
2429+
unlink("test_file");
2430+
2431+
loop = uv_default_loop();
2432+
2433+
iovs = malloc(sizeof(*iovs) * iovcount);
2434+
ASSERT(iovs != NULL);
2435+
2436+
r = uv_fs_open(loop,
2437+
&open_req1,
2438+
"test_file",
2439+
O_RDWR | O_CREAT,
2440+
S_IWUSR | S_IRUSR,
2441+
NULL);
2442+
ASSERT(r >= 0);
2443+
ASSERT(open_req1.result >= 0);
2444+
uv_fs_req_cleanup(&open_req1);
2445+
2446+
iov = uv_buf_init(filler, filler_len);
2447+
r = uv_fs_write(loop, &write_req, open_req1.result, &iov, 1, -1, NULL);
2448+
ASSERT(r == filler_len);
2449+
ASSERT(write_req.result == filler_len);
2450+
uv_fs_req_cleanup(&write_req);
2451+
offset = (int64_t)r;
2452+
2453+
for (index = 0; index < iovcount; ++index)
2454+
iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
2455+
2456+
r = uv_fs_write(loop,
2457+
&write_req,
2458+
open_req1.result,
2459+
iovs,
2460+
iovcount,
2461+
offset,
2462+
NULL);
2463+
ASSERT(r >= 0);
2464+
ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
2465+
uv_fs_req_cleanup(&write_req);
2466+
2467+
/* Read the strings back to separate buffers. */
2468+
buffer = malloc(sizeof(test_buf) * iovcount);
2469+
ASSERT(buffer != NULL);
2470+
2471+
for (index = 0; index < iovcount; ++index)
2472+
iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
2473+
sizeof(test_buf));
2474+
2475+
r = uv_fs_read(loop, &read_req, open_req1.result, iovs, iovcount, offset, NULL);
2476+
ASSERT(r >= 0);
2477+
ASSERT(read_req.result == sizeof(test_buf) * iovcount);
2478+
2479+
for (index = 0; index < iovcount; ++index)
2480+
ASSERT(strncmp(buffer + index * sizeof(test_buf),
2481+
test_buf,
2482+
sizeof(test_buf)) == 0);
2483+
2484+
uv_fs_req_cleanup(&read_req);
2485+
free(buffer);
2486+
2487+
r = uv_fs_stat(loop, &stat_req, "test_file", NULL);
2488+
ASSERT(r == 0);
2489+
ASSERT((int64_t)((uv_stat_t*)stat_req.ptr)->st_size ==
2490+
offset + (int64_t)(iovcount * sizeof(test_buf)));
2491+
uv_fs_req_cleanup(&stat_req);
2492+
2493+
iov = uv_buf_init(buf, sizeof(buf));
2494+
r = uv_fs_read(loop,
2495+
&read_req,
2496+
open_req1.result,
2497+
&iov,
2498+
1,
2499+
read_req.result + offset,
2500+
NULL);
2501+
ASSERT(r == 0);
2502+
ASSERT(read_req.result == 0);
2503+
uv_fs_req_cleanup(&read_req);
2504+
2505+
r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
2506+
ASSERT(r == 0);
2507+
ASSERT(close_req.result == 0);
2508+
uv_fs_req_cleanup(&close_req);
2509+
2510+
/* Cleanup */
2511+
unlink("test_file");
2512+
free(iovs);
2513+
2514+
MAKE_VALGRIND_HAPPY();
2515+
return 0;
2516+
}

test/test-list.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ TEST_DECLARE (fs_scandir_file)
278278
TEST_DECLARE (fs_open_dir)
279279
TEST_DECLARE (fs_rename_to_existing_file)
280280
TEST_DECLARE (fs_write_multiple_bufs)
281+
TEST_DECLARE (fs_write_alotof_bufs)
282+
TEST_DECLARE (fs_write_alotof_bufs_with_offset)
281283
TEST_DECLARE (threadpool_queue_work_simple)
282284
TEST_DECLARE (threadpool_queue_work_einval)
283285
TEST_DECLARE (threadpool_multiple_event_loops)
@@ -692,6 +694,8 @@ TASK_LIST_START
692694
TEST_ENTRY (fs_open_dir)
693695
TEST_ENTRY (fs_rename_to_existing_file)
694696
TEST_ENTRY (fs_write_multiple_bufs)
697+
TEST_ENTRY (fs_write_alotof_bufs)
698+
TEST_ENTRY (fs_write_alotof_bufs_with_offset)
695699
TEST_ENTRY (threadpool_queue_work_simple)
696700
TEST_ENTRY (threadpool_queue_work_einval)
697701
TEST_ENTRY (threadpool_multiple_event_loops)

0 commit comments

Comments
 (0)