From 27030b17645d255ace49d67c5d0bc6b617c0d636 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Tue, 27 Sep 2011 12:21:26 -0400 Subject: [PATCH] removing copies from readdir path --- daemon/nfs41_daemon.c | 7 +---- daemon/readdir.c | 26 +++++------------- daemon/upcall.h | 1 + sys/nfs41_driver.c | 62 +++++++++++++++++++++++++++++++++++++++---- 4 files changed, 66 insertions(+), 30 deletions(-) diff --git a/daemon/nfs41_daemon.c b/daemon/nfs41_daemon.c index 5d3796e..3bd7edf 100644 --- a/daemon/nfs41_daemon.c +++ b/daemon/nfs41_daemon.c @@ -85,7 +85,7 @@ static unsigned int WINAPI thread_main(void *args) // buffer used to send downcall content, need to dynamically allocated // as we don't know the length of the buffer (ie. size of directory listing unsigned char *inbuf = NULL; - DWORD inbuf_len, outbuf_len; + DWORD inbuf_len = UPCALL_BUF_SIZE, outbuf_len; nfs41_upcall upcall; pipe = CreateFile(NFS41_USER_DEVICE_NAME_A, GENERIC_READ | GENERIC_WRITE, @@ -130,11 +130,6 @@ write_downcall: "get_last_error=%d\n", upcall.xid, opcode2string(upcall.opcode), upcall.status, upcall.last_error); - if (upcall.opcode == NFS41_DIR_QUERY) - inbuf_len = UPCALL_BUF_SIZE + upcall.args.readdir.query_reply_len; - else - inbuf_len = UPCALL_BUF_SIZE; - inbuf = malloc(inbuf_len); if (inbuf == NULL) { upcall.status = GetLastError(); diff --git a/daemon/readdir.c b/daemon/readdir.c index 811c254..e68164d 100644 --- a/daemon/readdir.c +++ b/daemon/readdir.c @@ -63,13 +63,15 @@ static int parse_readdir(unsigned char *buffer, uint32_t length, nfs41_upcall *u if (status) goto out; status = safe_read(&buffer, &length, &args->single, sizeof(args->single)); if (status) goto out; + status = safe_read(&buffer, &length, &args->kbuf, sizeof(args->kbuf)); + if (status) goto out; args->root = upcall->root_ref; args->state = upcall->state_ref; dprintf(1, "parsing NFS41_DIR_QUERY: info_class=%d buf_len=%d " - "filter='%s'\n\tInitial\\Restart\\Single %d\\%d\\%d\n", + "filter='%s'\n\tInitial\\Restart\\Single %d\\%d\\%d buf=%p\n", args->query_class, args->buf_len, args->filter, - args->initial, args->restart, args->single); + args->initial, args->restart, args->single, args->kbuf); out: return status; } @@ -479,13 +481,13 @@ static int handle_readdir(nfs41_upcall *upcall) goto out; } - entry_buf = malloc(max(args->buf_len, 4096)); + entry_buf = malloc(args->buf_len); if (entry_buf == NULL) { status = GetLastError(); goto out_free_cookie; } fetch_entries: - entry_buf_len = max(args->buf_len, 4096); + entry_buf_len = args->buf_len; init_getattr_request(&attr_request); attr_request.arr[0] |= FATTR4_WORD0_RDATTR_ERROR; @@ -550,20 +552,11 @@ fetch_entries: if (entry_buf_len) { unsigned char *entry_pos = entry_buf; - unsigned char *dst_pos; + unsigned char *dst_pos = args->kbuf; uint32_t dst_len = args->buf_len; nfs41_readdir_entry *entry; PULONG offset, last_offset = NULL; - if (args->buf == NULL) { - args->buf = malloc(args->buf_len); - if (args->buf == NULL) { - status = GetLastError(); - goto out_free_cookie; - } - } - dst_pos = args->buf; - for (;;) { entry = (nfs41_readdir_entry*)entry_pos; offset = (PULONG)dst_pos; /* ULONG NextEntryOffset */ @@ -625,7 +618,6 @@ out: dprintf(1, "error code %d.\n", status); break; } - free(args->buf); args->buf = NULL; } else { dprintf(1, "success!\n"); @@ -642,10 +634,6 @@ static int marshall_readdir(unsigned char *buffer, uint32_t *length, nfs41_upcal readdir_upcall_args *args = &upcall->args.readdir; status = safe_write(&buffer, length, &args->query_reply_len, sizeof(args->query_reply_len)); - if (status) goto out; - status = safe_write(&buffer, length, args->buf, args->query_reply_len); -out: - free(args->buf); return status; } diff --git a/daemon/upcall.h b/daemon/upcall.h index 3606307..1b73827 100644 --- a/daemon/upcall.h +++ b/daemon/upcall.h @@ -132,6 +132,7 @@ typedef struct __readdir_upcall_args { BOOLEAN initial; BOOLEAN restart; BOOLEAN single; + unsigned char *kbuf; } readdir_upcall_args; typedef struct __symlink_upcall_args { diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index 16e98c4..94855ed 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -186,6 +186,8 @@ typedef struct _updowncall_entry { BOOLEAN restart_scan; BOOLEAN return_single; BOOLEAN initial_query; + PMDL mdl; + PVOID mdl_buf; } QueryFile; struct { PUNICODE_STRING filename; @@ -831,7 +833,7 @@ NTSTATUS marshal_nfs41_dirquery(nfs41_updowncall_entry *entry, else tmp += *len; - header_len = *len + 2 * sizeof(ULONG) + + header_len = *len + 2 * sizeof(ULONG) + sizeof(HANDLE) + length_as_ansi(entry->u.QueryFile.filter) + 3 * sizeof(BOOLEAN); if (header_len > buf_len) { status = STATUS_INSUFFICIENT_RESOURCES; @@ -849,13 +851,34 @@ NTSTATUS marshal_nfs41_dirquery(nfs41_updowncall_entry *entry, RtlCopyMemory(tmp, &entry->u.QueryFile.restart_scan, sizeof(BOOLEAN)); tmp += sizeof(BOOLEAN); RtlCopyMemory(tmp, &entry->u.QueryFile.return_single, sizeof(BOOLEAN)); - + tmp += sizeof(BOOLEAN); + __try { + MmProbeAndLockPages(entry->u.QueryFile.mdl, KernelMode, IoModifyAccess); + entry->u.QueryFile.mdl_buf = + MmMapLockedPagesSpecifyCache(entry->u.QueryFile.mdl, + UserMode, MmNonCached, NULL, TRUE, NormalPagePriority); + if (entry->u.QueryFile.mdl_buf == NULL) { + print_error("MmMapLockedPagesSpecifyCache failed to map pages\n"); + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + DbgP("MdlAddress=%p Userspace=%p\n", entry->u.QueryFile.mdl, + entry->u.QueryFile.mdl_buf); + } __except(EXCEPTION_EXECUTE_HANDLER) { + NTSTATUS code; + code = GetExceptionCode(); + print_error("Call to MmMapLocked failed due to exception 0x%x\n", code); + status = STATUS_ACCESS_DENIED; + goto out; + } + RtlCopyMemory(tmp, &entry->u.QueryFile.mdl_buf, sizeof(HANDLE)); *len = header_len; - DbgP("marshal_nfs41_dirquery: filter='%wZ'class=%d " + DbgP("marshal_nfs41_dirquery: filter='%wZ'class=%d len=%d " "1st\\restart\\single=%d\\%d\\%d\n", entry->u.QueryFile.filter, - entry->u.QueryFile.InfoClass, entry->u.QueryFile.initial_query, - entry->u.QueryFile.restart_scan, entry->u.QueryFile.return_single); + entry->u.QueryFile.InfoClass, entry->u.QueryFile.buf_len, + entry->u.QueryFile.initial_query, entry->u.QueryFile.restart_scan, + entry->u.QueryFile.return_single); out: DbgEx(); return status; @@ -1568,6 +1591,26 @@ nfs41_downcall ( cur->open_state, cur->u.Open.mode, cur->u.Open.changeattr); break; case NFS41_DIR_QUERY: + RtlCopyMemory(&tmp->u.QueryFile.buf_len, buf, sizeof(ULONG)); + DbgP("readdir reply size %d\n", tmp->u.QueryFile.buf_len); + buf += sizeof(ULONG); + __try { + MmUnmapLockedPages(cur->u.QueryFile.mdl_buf, cur->u.QueryFile.mdl); + MmUnlockPages(cur->u.QueryFile.mdl); + } __except(EXCEPTION_EXECUTE_HANDLER) { + NTSTATUS code; + code = GetExceptionCode(); + print_error("Call to MmUnmapLockedPages failed due to" + " exception 0x%0x\n", code); + status = STATUS_ACCESS_DENIED; + } + if (tmp->u.QueryFile.buf_len > cur->u.QueryFile.buf_len) { + cur->status = STATUS_BUFFER_TOO_SMALL; + cur->u.QueryFile.buf_len = tmp->u.QueryFile.buf_len; + break; + } + cur->u.QueryFile.buf_len = tmp->u.QueryFile.buf_len; + break; case NFS41_FILE_QUERY: RtlCopyMemory(&tmp->u.QueryFile.buf_len, buf, sizeof(ULONG)); buf += sizeof(ULONG); @@ -3428,6 +3471,14 @@ NTSTATUS nfs41_QueryDirectory ( entry->u.QueryFile.InfoClass = InfoClass; entry->u.QueryFile.buf_len = RxContext->Info.LengthRemaining; entry->u.QueryFile.buf = RxContext->Info.Buffer; + entry->u.QueryFile.mdl = IoAllocateMdl(RxContext->Info.Buffer, + RxContext->Info.LengthRemaining, FALSE, FALSE, NULL); + if (entry->u.QueryFile.mdl == NULL) { + status = STATUS_INTERNAL_ERROR; + RxFreePool(entry); + goto out; + } + entry->u.QueryFile.filter = Filter; entry->u.QueryFile.initial_query = RxContext->QueryDirectory.InitialQuery; entry->u.QueryFile.restart_scan = RxContext->QueryDirectory.RestartScan; @@ -3454,6 +3505,7 @@ NTSTATUS nfs41_QueryDirectory ( /* map windows ERRORs to NTSTATUS */ status = map_querydir_errors(entry->status); } + IoFreeMdl(entry->u.QueryFile.mdl); RxFreePool(entry); out: #ifdef ENABLE_TIMINGS