readdir cookie is stored with nfs41_open_state

fixes a memory leak that occurs when a readdir loop doesn't complete, since the cookie was only freed on the last readdir upcall.  by storing the cookie with nfs41_open_state, we can avoid passing the cookie to the driver and back, and not worry about having to free it separately

Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
Casey Bodley 2010-10-27 14:31:06 -04:00
parent 4930e7caca
commit 7e7f73766d
6 changed files with 33 additions and 57 deletions

View file

@ -76,6 +76,7 @@ typedef struct __nfs41_open_state {
nfs41_abs_path path;
nfs41_path_fh parent;
nfs41_path_fh file;
nfs41_readdir_cookie cookie;
struct __nfs41_session *session;
uint32_t type;
bool_t do_close;

View file

@ -643,11 +643,6 @@ typedef struct __nfs41_read_res {
/* OP_READDIR */
typedef struct __nfs41_readdir_cookie {
uint64_t cookie;
unsigned char verf[NFS4_VERIFIER_SIZE];
} nfs41_readdir_cookie;
typedef struct __nfs41_readdir_args {
nfs41_readdir_cookie cookie;
uint32_t dircount;

View file

@ -69,6 +69,11 @@ typedef struct __nfs41_fsid {
uint64_t minor;
} nfs41_fsid;
typedef struct __nfs41_readdir_cookie {
uint64_t cookie;
unsigned char verf[NFS4_VERIFIER_SIZE];
} nfs41_readdir_cookie;
typedef struct __netaddr4 {
char netid[NFS41_NETWORK_ID_LEN+1];
char uaddr[NFS41_UNIVERSAL_ADDR_LEN+1];

View file

@ -64,18 +64,13 @@ int parse_readdir(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
if (status) goto out;
status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
if (status) goto out;
status = safe_read(&buffer, &length, &args->cookie, sizeof(args->cookie));
if (status) goto out;
if (args->cookie == INVALID_HANDLE_VALUE) {
dprintf(1, "upcall passing empty cookie\n");
args->cookie = NULL;
}
dprintf(1, "parsing NFS41_DIR_QUERY: info_class=%d buf_len=%d "
"filter='%s'\n\tInitial\\Restart\\Single %d\\%d\\%d "
"root=0x%p state=0x%p cookie=0x%p\n",
"root=0x%p state=0x%p\n",
args->query_class, args->buf_len, args->filter,
args->initial, args->restart, args->single,
args->root, args->state, args->cookie);
args->root, args->state);
out:
return status;
}
@ -391,7 +386,7 @@ int readdir_add_dots(
*len_out = 0;
*last_offset = NULL;
switch (args->cookie->cookie) {
switch (state->cookie.cookie) {
case 0:
if (entry_buf_len < entry_len + 2) {
status = ERROR_BUFFER_OVERFLOW;
@ -451,9 +446,9 @@ int readdir_add_dots(
*last_offset = &entry->next_entry_offset;
break;
}
if (args->cookie->cookie == COOKIE_DOTDOT ||
args->cookie->cookie == COOKIE_DOT)
ZeroMemory(args->cookie, sizeof(nfs41_readdir_cookie));
if (state->cookie.cookie == COOKIE_DOTDOT ||
state->cookie.cookie == COOKIE_DOT)
ZeroMemory(&state->cookie, sizeof(nfs41_readdir_cookie));
out:
return status;
}
@ -474,26 +469,22 @@ int handle_readdir(nfs41_upcall *upcall)
args->buf = NULL;
args->query_reply_len = 0;
if (args->cookie) { /* cookie exists */
if (state->cookie.cookie) { /* cookie exists */
if (args->restart) {
dprintf(1, "restarting; clearing previous cookie (%d %p)\n",
args->cookie->cookie, args->cookie);
ZeroMemory(args->cookie, sizeof(nfs41_readdir_cookie));
dprintf(1, "restarting; clearing previous cookie %llu\n",
state->cookie.cookie);
ZeroMemory(&state->cookie, sizeof(nfs41_readdir_cookie));
} else if (args->initial) { /* shouldn't happen */
dprintf(1, "*** initial; clearing previous cookie (%d %p)!\n",
args->cookie->cookie, args->cookie);
ZeroMemory(args->cookie, sizeof(nfs41_readdir_cookie));
dprintf(1, "*** initial; clearing previous cookie %llu!\n",
state->cookie.cookie);
ZeroMemory(&state->cookie, sizeof(nfs41_readdir_cookie));
} else
dprintf(1, "resuming enumeration with cookie %d.\n",
args->cookie->cookie);
dprintf(1, "resuming enumeration with cookie %llu.\n",
state->cookie.cookie);
} else { /* cookie is null */
if (args->initial || args->restart) {
dprintf(1, "allocating memory for the 1st readdir cookie\n");
args->cookie = calloc(1, sizeof(nfs41_readdir_cookie));
if (args->cookie == NULL) {
status = GetLastError();
goto out;
}
dprintf(1, "initializing the 1st readdir cookie\n");
ZeroMemory(&state->cookie, sizeof(nfs41_readdir_cookie));
} else {
dprintf(1, "handle_nfs41_readdir: EOF\n");
status = ERROR_NO_MORE_FILES;
@ -532,10 +523,10 @@ fetch_entries:
entry_buf_len = 0;
eof = 0;
} else {
dprintf(2, "calling nfs41_readdir with cookie %d %p \n",
args->cookie->cookie, args->cookie);
dprintf(2, "calling nfs41_readdir with cookie %llu\n",
state->cookie.cookie);
status = nfs41_readdir(state->session, &state->file,
&attr_request, args->cookie, entry_buf + dots_len,
&attr_request, &state->cookie, entry_buf + dots_len,
&entry_buf_len, &eof);
if (status) {
dprintf(1, "nfs41_readdir failed with %s\n",
@ -602,7 +593,7 @@ fetch_entries:
last_offset = offset;
status = NO_ERROR;
}
args->cookie->cookie = entry->cookie;
state->cookie.cookie = entry->cookie;
/* last entry we got from the server */
if (!entry->next_entry_offset)
@ -628,7 +619,7 @@ fetch_entries:
dprintf(1, "we don't need to save a cookie\n");
goto out_free_cookie;
} else
dprintf(1, "saving cookie %d %p\n", args->cookie->cookie, args->cookie);
dprintf(1, "saving cookie %llu\n", state->cookie.cookie);
out_free_entry:
free(entry_buf);
@ -654,8 +645,7 @@ out:
}
return status;
out_free_cookie:
free(args->cookie);
args->cookie = NULL;
state->cookie.cookie = 0;
goto out_free_entry;
}
@ -667,8 +657,6 @@ int marshall_readdir(unsigned char *buffer, uint32_t *length, nfs41_upcall *upca
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);
if (status) goto out;
status = safe_write(&buffer, length, &args->cookie, sizeof(args->cookie));
out:
free(args->buf);
return status;

View file

@ -123,7 +123,6 @@ typedef struct __setexattr_upcall_args {
typedef struct __readdir_upcall_args {
const char *filter;
nfs41_readdir_cookie *cookie;
nfs41_root *root;
nfs41_open_state *state;
unsigned char *buf;