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:
parent
006bdfa47a
commit
bcc707d3b8
13 changed files with 57 additions and 4 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue