diff --git a/daemon/nfs41.h b/daemon/nfs41.h index 7123f90..6ab2543 100644 --- a/daemon/nfs41.h +++ b/daemon/nfs41.h @@ -91,6 +91,7 @@ typedef struct __nfs41_open_state { state_owner4 owner; nfs41_lock_state last_lock; struct __pnfs_file_layout *layout; + struct list_entry client_entry; /* entry in nfs41_client.opens */ SRWLOCK lock; LONG ref_count; } nfs41_open_state; @@ -109,6 +110,11 @@ typedef struct __nfs41_rpc_clnt { bool_t in_recovery; } nfs41_rpc_clnt; +struct client_state { + struct list_entry opens; /* list of associated nfs41_open_state */ + CRITICAL_SECTION lock; +}; + typedef struct __nfs41_client { nfs41_server *server; client_owner4 owner; @@ -126,6 +132,9 @@ typedef struct __nfs41_client { HANDLE cond; struct __nfs41_root *root; bool_t in_recovery; + + /* for state recovery on server reboot */ + struct client_state state; } nfs41_client; #define NFS41_MAX_NUM_SLOTS NFS41_MAX_RPC_REQS diff --git a/daemon/nfs41_client.c b/daemon/nfs41_client.c index 96711c3..ad5572c 100644 --- a/daemon/nfs41_client.c +++ b/daemon/nfs41_client.c @@ -131,6 +131,9 @@ int nfs41_client_create( client->is_data = is_data; update_exchangeid_res(client, exchangeid); + list_init(&client->state.opens); + InitializeCriticalSection(&client->state.lock); + //initialize a lock used to protect access to client id and client id seq# InitializeSRWLock(&client->exid_lock); diff --git a/daemon/open.c b/daemon/open.c index 15630d7..6de0469 100644 --- a/daemon/open.c +++ b/daemon/open.c @@ -73,6 +73,7 @@ out_free: goto out; } +/* open state reference counting */ void nfs41_open_state_ref( IN nfs41_open_state *state) { @@ -94,6 +95,28 @@ void nfs41_open_state_deref( } +/* client list of associated open state */ +static void client_state_add( + IN nfs41_open_state *state) +{ + nfs41_client *client = state->session->client; + + EnterCriticalSection(&client->state.lock); + list_add_tail(&client->state.opens, &state->client_entry); + LeaveCriticalSection(&client->state.lock); +} + +static void client_state_remove( + IN nfs41_open_state *state) +{ + nfs41_client *client = state->session->client; + + EnterCriticalSection(&client->state.lock); + list_remove(&state->client_entry); + LeaveCriticalSection(&client->state.lock); +} + + /* NFS41_OPEN */ static int parse_open(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) { @@ -395,6 +418,9 @@ static int handle_open(nfs41_upcall *upcall) args->mode, state, &info); if (status == NFS4_OK) { + /* add to the client's list of state for recovery */ + client_state_add(state); + nfs_to_basic_info(&info, &args->basic_info); nfs_to_standard_info(&info, &args->std_info); state->do_close = 1; @@ -468,6 +494,9 @@ static void cancel_open(IN nfs41_upcall *upcall) if (status) dprintf(1, "cancel_open: nfs41_close() failed with %s\n", nfs_error_string(status)); + + /* remove from the client's list of state for recovery */ + client_state_remove(state); } else if (args->created) { const nfs41_component *name = &state->file.name; status = nfs41_remove(state->session, &state->parent, name); @@ -545,6 +574,9 @@ static int handle_close(nfs41_upcall *upcall) nfs_error_string(status)); status = nfs_to_windows_error(status, ERROR_INTERNAL_ERROR); } + + /* remove from the client's list of state for recovery */ + client_state_remove(state); } if (status || !rm_status)