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;
|
||||
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
|
||||
if (status) goto out;
|
||||
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);
|
||||
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->offset, sizeof(LONGLONG));
|
||||
if (status) goto out;
|
||||
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);
|
||||
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->count, sizeof(ULONG));
|
||||
if (status) goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ out:
|
|||
return status;
|
||||
|
||||
out_err:
|
||||
nfs41_root_free(root);
|
||||
nfs41_root_deref(root);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +136,8 @@ static int handle_unmount(nfs41_upcall *upcall)
|
|||
{
|
||||
int status = NO_ERROR;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ int nfs41_root_create(
|
|||
root->wsize = wsize;
|
||||
root->rsize = rsize;
|
||||
InitializeCriticalSection(&root->lock);
|
||||
root->ref_count = 1;
|
||||
|
||||
/* generate a unique client_owner */
|
||||
status = nfs41_client_owner(name, &root->client_owner);
|
||||
|
|
@ -71,7 +72,7 @@ out:
|
|||
return status;
|
||||
}
|
||||
|
||||
void nfs41_root_free(
|
||||
static void root_free(
|
||||
IN nfs41_root *root)
|
||||
{
|
||||
struct list_entry *entry, *tmp;
|
||||
|
|
@ -86,6 +87,25 @@ void nfs41_root_free(
|
|||
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() */
|
||||
struct cl_addr_info {
|
||||
const multi_addr4 *addrs;
|
||||
|
|
|
|||
|
|
@ -168,12 +168,18 @@ typedef struct __nfs41_session {
|
|||
nfs41_cb_session cb_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 {
|
||||
client_owner4 client_owner;
|
||||
CRITICAL_SECTION lock;
|
||||
struct list_entry clients;
|
||||
uint32_t wsize;
|
||||
uint32_t rsize;
|
||||
LONG ref_count;
|
||||
} nfs41_root;
|
||||
|
||||
|
||||
|
|
@ -184,7 +190,10 @@ int nfs41_root_create(
|
|||
IN uint32_t rsize,
|
||||
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);
|
||||
|
||||
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;
|
||||
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->open_owner_id, sizeof(ULONG));
|
||||
if (status) goto out;
|
||||
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));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->state, sizeof(nfs41_open_state *));
|
||||
if (status) goto out;
|
||||
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;
|
||||
status = safe_read(&buffer, &length, &args->root, sizeof(args->root));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
|
||||
if (status) goto out;
|
||||
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;
|
||||
status = safe_read(&buffer, &length, &args->root, sizeof(args->root));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
|
||||
if (status) goto out;
|
||||
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));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
|
||||
if (status) goto out;
|
||||
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));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->state, sizeof(nfs41_open_state *));
|
||||
if (status) goto out;
|
||||
upcall_open_state_ref(upcall, args->state);
|
||||
|
|
|
|||
|
|
@ -186,4 +186,8 @@ void upcall_cleanup(
|
|||
nfs41_open_state_deref(upcall->state_ref);
|
||||
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
|
||||
* automatic dereferencing on upcall_cleanup();
|
||||
* see upcall_root_ref() and upcall_open_state_ref() */
|
||||
nfs41_root *root_ref;
|
||||
nfs41_open_state *state_ref;
|
||||
} nfs41_upcall;
|
||||
|
||||
|
|
@ -222,6 +223,14 @@ void upcall_cleanup(
|
|||
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(
|
||||
IN nfs41_upcall *upcall,
|
||||
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;
|
||||
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
|
||||
if (status) goto out;
|
||||
upcall_root_ref(upcall, args->root);
|
||||
status = safe_read(&buffer, &length, &args->query, sizeof(FS_INFORMATION_CLASS));
|
||||
if (status) goto out;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue