ref counting for nfs41_root

very similar to the issue with nfs41_open_state, an abandoned upcall could outlive its mount. to prevent their nfs41_root from being freed, upcalls need to hold a reference until they're finished. this also keeps all of its clients/sessions/rpc connections alive

Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
Casey Bodley 2010-10-27 13:36:22 -04:00 committed by unknown
parent 006bdfa47a
commit bcc707d3b8
13 changed files with 57 additions and 4 deletions

View file

@ -69,6 +69,7 @@ static int parse_getattr(unsigned char *buffer, uint32_t length, nfs41_upcall *u
if (status) goto out; if (status) goto out;
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->state, sizeof(args->state)); status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
if (status) goto out; if (status) goto out;
upcall_open_state_ref(upcall, args->state); upcall_open_state_ref(upcall, args->state);

View file

@ -97,6 +97,7 @@ static int parse_lock(unsigned char *buffer, uint32_t length, nfs41_upcall *upca
upcall_open_state_ref(upcall, args->state); upcall_open_state_ref(upcall, args->state);
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->offset, sizeof(LONGLONG)); status = safe_read(&buffer, &length, &args->offset, sizeof(LONGLONG));
if (status) goto out; if (status) goto out;
status = safe_read(&buffer, &length, &args->length, sizeof(LONGLONG)); status = safe_read(&buffer, &length, &args->length, sizeof(LONGLONG));
@ -185,6 +186,7 @@ static int parse_unlock(unsigned char *buffer, uint32_t length, nfs41_upcall *up
upcall_open_state_ref(upcall, args->state); upcall_open_state_ref(upcall, args->state);
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->count, sizeof(ULONG)); status = safe_read(&buffer, &length, &args->count, sizeof(ULONG));
if (status) goto out; if (status) goto out;

View file

@ -100,7 +100,7 @@ out:
return status; return status;
out_err: out_err:
nfs41_root_free(root); nfs41_root_deref(root);
goto out; goto out;
} }
@ -136,7 +136,8 @@ static int handle_unmount(nfs41_upcall *upcall)
{ {
int status = NO_ERROR; int status = NO_ERROR;
unmount_upcall_args *args = &upcall->args.unmount; unmount_upcall_args *args = &upcall->args.unmount;
nfs41_root_free(args->root); /* release the original reference from nfs41_root_create() */
nfs41_root_deref(args->root);
return status; return status;
} }

View file

@ -57,6 +57,7 @@ int nfs41_root_create(
root->wsize = wsize; root->wsize = wsize;
root->rsize = rsize; root->rsize = rsize;
InitializeCriticalSection(&root->lock); InitializeCriticalSection(&root->lock);
root->ref_count = 1;
/* generate a unique client_owner */ /* generate a unique client_owner */
status = nfs41_client_owner(name, &root->client_owner); status = nfs41_client_owner(name, &root->client_owner);
@ -71,7 +72,7 @@ out:
return status; return status;
} }
void nfs41_root_free( static void root_free(
IN nfs41_root *root) IN nfs41_root *root)
{ {
struct list_entry *entry, *tmp; struct list_entry *entry, *tmp;
@ -86,6 +87,25 @@ void nfs41_root_free(
dprintf(NSLVL, "<-- nfs41_root_free()\n"); dprintf(NSLVL, "<-- nfs41_root_free()\n");
} }
void nfs41_root_ref(
IN nfs41_root *root)
{
const LONG count = InterlockedIncrement(&root->ref_count);
dprintf(2, "nfs41_root_ref() count %d\n", count);
}
void nfs41_root_deref(
IN nfs41_root *root)
{
const LONG count = InterlockedDecrement(&root->ref_count);
dprintf(2, "nfs41_root_deref() count %d\n", count);
if (count == 0)
root_free(root);
}
/* root_client_find_addrs() */ /* root_client_find_addrs() */
struct cl_addr_info { struct cl_addr_info {
const multi_addr4 *addrs; const multi_addr4 *addrs;

View file

@ -168,12 +168,18 @@ typedef struct __nfs41_session {
nfs41_cb_session cb_session; nfs41_cb_session cb_session;
} nfs41_session; } nfs41_session;
/* nfs41_root reference counting:
* similar to nfs41_open_state, the driver holds an implicit reference
* between MOUNT and UNMOUNT. all other upcalls use upcall_root_ref() on
* upcall_parse(), which prevents the root/clients from being freed and
* guarantees a matching deref on upcall_cleanup() */
typedef struct __nfs41_root { typedef struct __nfs41_root {
client_owner4 client_owner; client_owner4 client_owner;
CRITICAL_SECTION lock; CRITICAL_SECTION lock;
struct list_entry clients; struct list_entry clients;
uint32_t wsize; uint32_t wsize;
uint32_t rsize; uint32_t rsize;
LONG ref_count;
} nfs41_root; } nfs41_root;
@ -184,7 +190,10 @@ int nfs41_root_create(
IN uint32_t rsize, IN uint32_t rsize,
OUT nfs41_root **root_out); OUT nfs41_root **root_out);
void nfs41_root_free( void nfs41_root_ref(
IN nfs41_root *root);
void nfs41_root_deref(
IN nfs41_root *root); IN nfs41_root *root);
int nfs41_root_mount_addrs( int nfs41_root_mount_addrs(

View file

@ -121,6 +121,7 @@ static int parse_open(unsigned char *buffer, uint32_t length, nfs41_upcall *upca
if (status) goto out; if (status) goto out;
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->open_owner_id, sizeof(ULONG)); status = safe_read(&buffer, &length, &args->open_owner_id, sizeof(ULONG));
if (status) goto out; if (status) goto out;
status = safe_read(&buffer, &length, &args->mode, sizeof(DWORD)); status = safe_read(&buffer, &length, &args->mode, sizeof(DWORD));
@ -497,6 +498,7 @@ static int parse_close(unsigned char *buffer, uint32_t length, nfs41_upcall *upc
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->state, sizeof(nfs41_open_state *)); status = safe_read(&buffer, &length, &args->state, sizeof(nfs41_open_state *));
if (status) goto out; if (status) goto out;
status = safe_read(&buffer, &length, &args->remove, sizeof(BOOLEAN)); status = safe_read(&buffer, &length, &args->remove, sizeof(BOOLEAN));

View file

@ -62,6 +62,7 @@ static int parse_readdir(unsigned char *buffer, uint32_t length, nfs41_upcall *u
if (status) goto out; if (status) goto out;
status = safe_read(&buffer, &length, &args->root, sizeof(args->root)); status = safe_read(&buffer, &length, &args->root, sizeof(args->root));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->state, sizeof(args->state)); status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
if (status) goto out; if (status) goto out;
upcall_open_state_ref(upcall, args->state); upcall_open_state_ref(upcall, args->state);

View file

@ -47,6 +47,7 @@ static int parse_rw(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall
if (status) goto out; if (status) goto out;
status = safe_read(&buffer, &length, &args->root, sizeof(args->root)); status = safe_read(&buffer, &length, &args->root, sizeof(args->root));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->state, sizeof(args->state)); status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
if (status) goto out; if (status) goto out;
upcall_open_state_ref(upcall, args->state); upcall_open_state_ref(upcall, args->state);

View file

@ -500,6 +500,7 @@ static int parse_setexattr(unsigned char *buffer, uint32_t length, nfs41_upcall
status = safe_read(&buffer, &length, &args->root, sizeof(args->root)); status = safe_read(&buffer, &length, &args->root, sizeof(args->root));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->state, sizeof(args->state)); status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
if (status) goto out; if (status) goto out;
upcall_open_state_ref(upcall, args->state); upcall_open_state_ref(upcall, args->state);

View file

@ -197,6 +197,7 @@ static int parse_symlink(unsigned char *buffer, uint32_t length, nfs41_upcall *u
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->state, sizeof(nfs41_open_state *)); status = safe_read(&buffer, &length, &args->state, sizeof(nfs41_open_state *));
if (status) goto out; if (status) goto out;
upcall_open_state_ref(upcall, args->state); upcall_open_state_ref(upcall, args->state);

View file

@ -186,4 +186,8 @@ void upcall_cleanup(
nfs41_open_state_deref(upcall->state_ref); nfs41_open_state_deref(upcall->state_ref);
upcall->state_ref = NULL; upcall->state_ref = NULL;
} }
if (upcall->root_ref) {
nfs41_root_deref(upcall->root_ref);
upcall->root_ref = NULL;
}
} }

View file

@ -180,6 +180,7 @@ typedef struct __nfs41_upcall {
/* store referenced pointers with the upcall for /* store referenced pointers with the upcall for
* automatic dereferencing on upcall_cleanup(); * automatic dereferencing on upcall_cleanup();
* see upcall_root_ref() and upcall_open_state_ref() */ * see upcall_root_ref() and upcall_open_state_ref() */
nfs41_root *root_ref;
nfs41_open_state *state_ref; nfs41_open_state *state_ref;
} nfs41_upcall; } nfs41_upcall;
@ -222,6 +223,14 @@ void upcall_cleanup(
IN nfs41_upcall *upcall); IN nfs41_upcall *upcall);
static __inline void upcall_root_ref(
IN nfs41_upcall *upcall,
IN nfs41_root *root)
{
nfs41_root_ref(root);
upcall->root_ref = root;
}
static __inline void upcall_open_state_ref( static __inline void upcall_open_state_ref(
IN nfs41_upcall *upcall, IN nfs41_upcall *upcall,
IN nfs41_open_state *state) IN nfs41_open_state *state)

View file

@ -48,6 +48,7 @@ static int parse_volume(unsigned char *buffer, uint32_t length, nfs41_upcall *up
volume_upcall_args *args = &upcall->args.volume; volume_upcall_args *args = &upcall->args.volume;
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
if (status) goto out; if (status) goto out;
upcall_root_ref(upcall, args->root);
status = safe_read(&buffer, &length, &args->query, sizeof(FS_INFORMATION_CLASS)); status = safe_read(&buffer, &length, &args->query, sizeof(FS_INFORMATION_CLASS));
if (status) goto out; if (status) goto out;