ReactOS 0.4.15-dev-7924-g5949c20
delegation.c File Reference
#include "delegation.h"
#include "nfs41_ops.h"
#include "name_cache.h"
#include "util.h"
#include "daemon_debug.h"
#include <devioctl.h>
#include "nfs41_driver.h"
Include dependency graph for delegation.c:

Go to the source code of this file.

Classes

struct  recall_thread_args
 

Macros

#define DGLVL   2 /* dprintf level for delegation logging */
 
#define open_entry(pos)   list_container(pos, nfs41_open_state, client_entry)
 
#define lock_entry(pos)   list_container(pos, nfs41_lock_state, open_entry)
 
#define deleg_entry(pos)   list_container(pos, nfs41_delegation_state, client_entry)
 

Functions

static int delegation_create (IN const nfs41_path_fh *parent, IN const nfs41_path_fh *file, IN const open_delegation4 *delegation, OUT nfs41_delegation_state **deleg_out)
 
void nfs41_delegation_ref (IN nfs41_delegation_state *state)
 
void nfs41_delegation_deref (IN nfs41_delegation_state *state)
 
static void delegation_remove (IN nfs41_client *client, IN nfs41_delegation_state *deleg)
 
static bool_t has_delegated_locks (IN nfs41_open_state *open)
 
static int open_deleg_cmp (const struct list_entry *entry, const void *value)
 
static nfs41_open_statedeleg_open_find (IN struct client_state *state, IN const nfs41_delegation_state *deleg)
 
static bool_t deleg_lock_find (IN nfs41_open_state *open, OUT nfs41_lock_state *lock_out)
 
static void deleg_lock_update (IN nfs41_open_state *open, IN const nfs41_lock_state *source)
 
static int delegation_flush_locks (IN nfs41_open_state *open, IN bool_t try_recovery)
 
static int delegation_return (IN nfs41_client *client, IN nfs41_delegation_state *deleg, IN bool_t truncate, IN bool_t try_recovery)
 
int nfs41_delegation_granted (IN nfs41_session *session, IN nfs41_path_fh *parent, IN nfs41_path_fh *file, IN open_delegation4 *delegation, IN bool_t try_recovery, OUT nfs41_delegation_state **deleg_out)
 
static int deleg_file_cmp (const struct list_entry *entry, const void *value)
 
static bool_t delegation_compatible (IN enum open_delegation_type4 type, IN uint32_t create, IN uint32_t access, IN uint32_t deny)
 
static int delegation_find (IN nfs41_client *client, IN const void *value, IN list_compare_fn cmp, OUT nfs41_delegation_state **deleg_out)
 
static int delegation_truncate (IN nfs41_delegation_state *deleg, IN nfs41_client *client, IN stateid_arg *stateid, IN nfs41_file_info *info)
 
int nfs41_delegate_open (IN nfs41_open_state *state, IN uint32_t create, IN OPTIONAL nfs41_file_info *createattrs, OUT nfs41_file_info *info)
 
int nfs41_delegation_to_open (IN nfs41_open_state *open, IN bool_t try_recovery)
 
void nfs41_delegation_remove_srvopen (IN nfs41_session *session, IN nfs41_path_fh *file)
 
int nfs41_delegation_return (IN nfs41_session *session, IN nfs41_path_fh *file, IN enum open_delegation_type4 access, IN bool_t truncate)
 
static unsigned int WINAPI delegation_recall_thread (void *args)
 
static int deleg_stateid_cmp (const struct list_entry *entry, const void *value)
 
int nfs41_delegation_recall (IN nfs41_client *client, IN nfs41_fh *fh, IN const stateid4 *stateid, IN bool_t truncate)
 
static int deleg_fh_cmp (const struct list_entry *entry, const void *value)
 
int nfs41_delegation_getattr (IN nfs41_client *client, IN const nfs41_fh *fh, IN const bitmap4 *attr_request, OUT nfs41_file_info *info)
 
void nfs41_client_delegation_free (IN nfs41_client *client)
 
static int delegation_recovery_status (IN nfs41_delegation_state *deleg)
 
int nfs41_client_delegation_recovery (IN nfs41_client *client)
 
int nfs41_client_delegation_return_lru (IN nfs41_client *client)
 

Macro Definition Documentation

◆ deleg_entry

Definition at line 377 of file delegation.c.

◆ DGLVL

#define DGLVL   2 /* dprintf level for delegation logging */

Definition at line 32 of file delegation.c.

◆ lock_entry

Definition at line 126 of file delegation.c.

◆ open_entry

Definition at line 89 of file delegation.c.

Function Documentation

◆ deleg_fh_cmp()

static int deleg_fh_cmp ( const struct list_entry entry,
const void value 
)
static

Definition at line 775 of file delegation.c.

776{
777 const nfs41_fh *lhs = &deleg_entry(entry)->file.fh;
778 const nfs41_fh *rhs = (const nfs41_fh*)value;
779 if (lhs->len != rhs->len) return -1;
780 return memcmp(lhs->fh, rhs->fh, lhs->len);
781}
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define deleg_entry(pos)
Definition: delegation.c:377
uint32_t entry
Definition: isohybrid.c:63
uint32_t len
Definition: nfs41_types.h:54
unsigned char fh[NFS4_FHSIZE]
Definition: nfs41_types.h:53
Definition: pdh_main.c:94

Referenced by nfs41_delegation_getattr().

◆ deleg_file_cmp()

static int deleg_file_cmp ( const struct list_entry entry,
const void value 
)
static

Definition at line 379 of file delegation.c.

380{
381 const nfs41_fh *lhs = &deleg_entry(entry)->file.fh;
382 const nfs41_fh *rhs = (const nfs41_fh*)value;
383 if (lhs->superblock != rhs->superblock) return -1;
384 if (lhs->fileid != rhs->fileid) return -1;
385 return 0;
386}
struct __nfs41_superblock * superblock
Definition: nfs41_types.h:56
uint64_t fileid
Definition: nfs41_types.h:55

Referenced by nfs41_delegate_open(), nfs41_delegation_remove_srvopen(), and nfs41_delegation_return().

◆ deleg_lock_find()

static bool_t deleg_lock_find ( IN nfs41_open_state open,
OUT nfs41_lock_state lock_out 
)
static

Definition at line 173 of file delegation.c.

176{
177 struct list_entry *entry;
178 bool_t found = FALSE;
179
181 list_for_each(entry, &open->locks.list) {
183 if (lock->delegated) {
184 /* copy offset, length, type */
185 lock_out->offset = lock->offset;
186 lock_out->length = lock->length;
187 lock_out->exclusive = lock->exclusive;
188 lock_out->id = lock->id;
189 found = TRUE;
190 break;
191 }
192 }
194 return found;
195}
#define open
Definition: acwin.h:95
#define list_for_each(entry, head)
Definition: list.h:36
#define lock_entry(pos)
Definition: delegation.c:126
int32_t bool_t
Definition: types.h:101
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:89
VOID WINAPI AcquireSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:61
Definition: list.h:27
rwlock_t lock
Definition: tcpcore.h:0

Referenced by delegation_flush_locks().

◆ deleg_lock_update()

static void deleg_lock_update ( IN nfs41_open_state open,
IN const nfs41_lock_state source 
)
static

Definition at line 198 of file delegation.c.

201{
202 struct list_entry *entry;
203
205 list_for_each(entry, &open->locks.list) {
207 if (lock->id == source->id) {
208 lock->delegated = FALSE;
209 break;
210 }
211 }
213}
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:54
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:82

Referenced by delegation_flush_locks().

◆ deleg_open_find()

static nfs41_open_state * deleg_open_find ( IN struct client_state state,
IN const nfs41_delegation_state deleg 
)
static

Definition at line 155 of file delegation.c.

158{
159 struct list_entry *entry;
161
163 entry = list_search(&state->opens, deleg, open_deleg_cmp);
164 if (entry) {
166 nfs41_open_state_ref(open); /* return a reference */
167 }
169 return open;
170}
static int state
Definition: maze.c:121
static struct list_entry * list_search(const struct list_entry *head, const void *value, list_compare_fn compare)
Definition: list.h:102
#define open_entry(pos)
Definition: delegation.c:89
static int open_deleg_cmp(const struct list_entry *entry, const void *value)
Definition: delegation.c:139
#define NULL
Definition: types.h:112
void nfs41_open_state_ref(IN nfs41_open_state *state)
Definition: open.c:96
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)

Referenced by delegation_return().

◆ deleg_stateid_cmp()

static int deleg_stateid_cmp ( const struct list_entry entry,
const void value 
)
static

Definition at line 696 of file delegation.c.

697{
698 const stateid4 *lhs = &deleg_entry(entry)->state.stateid;
699 const stateid4 *rhs = (const stateid4*)value;
700 return memcmp(lhs->other, rhs->other, NFS4_STATEID_OTHER);
701}
#define NFS4_STATEID_OTHER
Definition: nfs41_const.h:33
unsigned char other[NFS4_STATEID_OTHER]
Definition: nfs41_types.h:145

Referenced by nfs41_delegation_recall().

◆ delegation_compatible()

static bool_t delegation_compatible ( IN enum open_delegation_type4  type,
IN uint32_t  create,
IN uint32_t  access,
IN uint32_t  deny 
)
static

Definition at line 388 of file delegation.c.

393{
394 switch (type) {
396 /* An OPEN_DELEGATE_WRITE delegation allows the client to handle,
397 * on its own, all opens. */
398 return TRUE;
399
401 /* An OPEN_DELEGATE_READ delegation allows a client to handle,
402 * on its own, requests to open a file for reading that do not
403 * deny OPEN4_SHARE_ACCESS_READ access to others. */
404 if (create == OPEN4_CREATE)
405 return FALSE;
407 return FALSE;
408 return TRUE;
409
410 default:
411 return FALSE;
412 }
413}
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
static const struct access_res create[16]
Definition: package.c:7644
@ OPEN4_SHARE_ACCESS_WRITE
Definition: nfs41_ops.h:565
@ OPEN4_SHARE_DENY_READ
Definition: nfs41_ops.h:569
@ OPEN_DELEGATE_READ
Definition: nfs41_ops.h:587
@ OPEN_DELEGATE_WRITE
Definition: nfs41_ops.h:588
@ OPEN4_CREATE
Definition: nfs41_ops.h:554

Referenced by nfs41_delegate_open().

◆ delegation_create()

static int delegation_create ( IN const nfs41_path_fh parent,
IN const nfs41_path_fh file,
IN const open_delegation4 delegation,
OUT nfs41_delegation_state **  deleg_out 
)
static

Definition at line 36 of file delegation.c.

41{
43 int status = NO_ERROR;
44
46 if (state == NULL) {
48 goto out;
49 }
50
51 memcpy(&state->state, delegation, sizeof(open_delegation4));
52
53 abs_path_copy(&state->path, file->path);
54 path_fh_init(&state->file, &state->path);
55 fh_copy(&state->file.fh, &file->fh);
56 path_fh_init(&state->parent, &state->path);
57 last_component(state->path.path, state->file.name.name,
58 &state->parent.name);
59 fh_copy(&state->parent.fh, &parent->fh);
60
61 list_init(&state->client_entry);
62 state->status = DELEGATION_GRANTED;
65 state->ref_count = 1;
66 *deleg_out = state;
67out:
68 return status;
69}
static void list_init(struct list_entry *head)
Definition: list.h:51
void path_fh_init(OUT nfs41_path_fh *file, IN nfs41_abs_path *path)
Definition: util.c:346
bool_t last_component(IN const char *path, IN const char *path_end, OUT nfs41_component *component)
Definition: util.c:317
void fh_copy(OUT nfs41_fh *dst, IN const nfs41_fh *src)
Definition: util.c:354
void abs_path_copy(OUT nfs41_abs_path *dst, IN const nfs41_abs_path *src)
Definition: util.c:338
#define NO_ERROR
Definition: dderror.h:5
VOID WINAPI InitializeSRWLock(PSRWLOCK Lock)
Definition: sync.c:75
VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable)
Definition: sync.c:68
r parent
Definition: btrfs.c:3010
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
@ DELEGATION_GRANTED
Definition: nfs41.h:90
static FILE * out
Definition: regtests2xml.c:44
#define calloc
Definition: rosglue.h:14
Definition: fci.c:127
WCHAR * path
Definition: filesystem.c:122
Definition: ps.c:97
DWORD WINAPI GetLastError(void)
Definition: except.c:1042

Referenced by nfs41_delegation_granted().

◆ delegation_find()

static int delegation_find ( IN nfs41_client client,
IN const void value,
IN list_compare_fn  cmp,
OUT nfs41_delegation_state **  deleg_out 
)
static

Definition at line 415 of file delegation.c.

420{
421 struct list_entry *entry;
423
424 EnterCriticalSection(&client->state.lock);
425 entry = list_search(&client->state.delegations, value, cmp);
426 if (entry) {
427 /* return a reference to the delegation */
428 *deleg_out = deleg_entry(entry);
429 nfs41_delegation_ref(*deleg_out);
430
431 /* move to the 'most recently used' end of the list */
433 list_add_tail(&client->state.delegations, entry);
434 status = NFS4_OK;
435 }
436 LeaveCriticalSection(&client->state.lock);
437 return status;
438}
static void list_remove(struct list_entry *entry)
Definition: list.h:90
static void list_add_tail(struct list_entry *head, struct list_entry *entry)
Definition: list.h:83
void nfs41_delegation_ref(IN nfs41_delegation_state *state)
Definition: delegation.c:71
#define cmp(status, error)
Definition: error.c:114
@ NFS4_OK
Definition: nfs41_const.h:87
@ NFS4ERR_BADHANDLE
Definition: nfs41_const.h:107
static FILE * client
Definition: client.c:41

Referenced by nfs41_delegate_open(), nfs41_delegation_getattr(), nfs41_delegation_recall(), nfs41_delegation_remove_srvopen(), and nfs41_delegation_return().

◆ delegation_flush_locks()

static int delegation_flush_locks ( IN nfs41_open_state open,
IN bool_t  try_recovery 
)
static

Definition at line 215 of file delegation.c.

218{
219 stateid_arg stateid;
221 int status = NFS4_OK;
222
223 stateid.open = open;
224 stateid.delegation = NULL;
225
226 /* get the starting open/lock stateid */
228 if (open->locks.stateid.seqid) {
229 memcpy(&stateid.stateid, &open->locks.stateid, sizeof(stateid4));
230 stateid.type = STATEID_LOCK;
231 } else {
232 memcpy(&stateid.stateid, &open->stateid, sizeof(stateid4));
233 stateid.type = STATEID_OPEN;
234 }
236
237 /* send LOCK requests for each delegated lock range */
238 while (deleg_lock_find(open, &lock)) {
239 status = nfs41_lock(open->session, &open->file,
240 &open->owner, lock.exclusive ? WRITE_LT : READ_LT,
241 lock.offset, lock.length, FALSE, try_recovery, &stateid);
242 if (status)
243 break;
245 }
246
247 /* save the updated lock stateid */
248 if (stateid.type == STATEID_LOCK) {
250 if (open->locks.stateid.seqid == 0) {
251 /* if it's a new lock stateid, copy it in */
252 memcpy(&open->locks.stateid, &stateid.stateid, sizeof(stateid4));
253 } else if (stateid.stateid.seqid > open->locks.stateid.seqid) {
254 /* update the seqid if it's more recent */
255 open->locks.stateid.seqid = stateid.stateid.seqid;
256 }
258 }
259 return status;
260}
static void deleg_lock_update(IN nfs41_open_state *open, IN const nfs41_lock_state *source)
Definition: delegation.c:198
static bool_t deleg_lock_find(IN nfs41_open_state *open, OUT nfs41_lock_state *lock_out)
Definition: delegation.c:173
int nfs41_lock(IN nfs41_session *session, IN nfs41_path_fh *file, IN state_owner4 *owner, IN uint32_t type, IN uint64_t offset, IN uint64_t length, IN bool_t reclaim, IN bool_t try_recovery, IN OUT stateid_arg *stateid)
Definition: nfs41_ops.c:904
@ STATEID_LOCK
Definition: nfs41_ops.h:277
@ STATEID_OPEN
Definition: nfs41_ops.h:276
@ READ_LT
Definition: nfs41_ops.h:399
@ WRITE_LT
Definition: nfs41_ops.h:400
uint32_t seqid
Definition: nfs41_types.h:144
enum stateid_type type
Definition: nfs41_ops.h:285
nfs41_open_state * open
Definition: nfs41_ops.h:286
stateid4 stateid
Definition: nfs41_ops.h:284
nfs41_delegation_state * delegation
Definition: nfs41_ops.h:287

Referenced by delegation_return().

◆ delegation_recall_thread()

static unsigned int WINAPI delegation_recall_thread ( void args)
static

Definition at line 683 of file delegation.c.

684{
685 struct recall_thread_args *recall = (struct recall_thread_args*)args;
686
687 delegation_return(recall->client, recall->delegation, recall->truncate, TRUE);
688
689 /* clean up thread arguments */
691 nfs41_root_deref(recall->client->root);
692 free(recall);
693 return 0;
694}
#define free
Definition: debug_ros.c:5
static int delegation_return(IN nfs41_client *client, IN nfs41_delegation_state *deleg, IN bool_t truncate, IN bool_t try_recovery)
Definition: delegation.c:264
void nfs41_delegation_deref(IN nfs41_delegation_state *state)
Definition: delegation.c:79
void nfs41_root_deref(IN nfs41_root *root)
Definition: namespace.c:100
struct __nfs41_root * root
Definition: nfs41.h:206
Definition: match.c:390
nfs41_delegation_state * delegation
Definition: delegation.c:679
nfs41_client * client
Definition: delegation.c:678

Referenced by nfs41_delegation_recall().

◆ delegation_recovery_status()

static int delegation_recovery_status ( IN nfs41_delegation_state deleg)
static

Definition at line 842 of file delegation.c.

844{
845 int status = NFS4_OK;
846
847 AcquireSRWLockExclusive(&deleg->lock);
848 if (deleg->status == DELEGATION_GRANTED) {
849 if (deleg->revoked) {
850 deleg->status = DELEGATION_RETURNED;
852 } else if (deleg->state.recalled) {
853 deleg->status = DELEGATION_RETURNING;
855 }
856 }
857 ReleaseSRWLockExclusive(&deleg->lock);
858 return status;
859}
@ DELEGATION_RETURNED
Definition: nfs41.h:92
@ DELEGATION_RETURNING
Definition: nfs41.h:91
@ NFS4ERR_DELEG_REVOKED
Definition: nfs41_const.h:196

Referenced by nfs41_client_delegation_recovery().

◆ delegation_remove()

static void delegation_remove ( IN nfs41_client client,
IN nfs41_delegation_state deleg 
)
static

Definition at line 91 of file delegation.c.

94{
95 struct list_entry *entry;
96
97 /* remove from the client's list */
98 EnterCriticalSection(&client->state.lock);
99 list_remove(&deleg->client_entry);
100
101 /* remove from each associated open */
102 list_for_each(entry, &client->state.opens) {
105 if (open->delegation.state == deleg) {
106 /* drop the delegation reference */
107 nfs41_delegation_deref(open->delegation.state);
108 open->delegation.state = NULL;
109 }
111 }
112 LeaveCriticalSection(&client->state.lock);
113
114 /* signal threads waiting on delegreturn */
115 AcquireSRWLockExclusive(&deleg->lock);
116 deleg->status = DELEGATION_RETURNED;
117 WakeAllConditionVariable(&deleg->cond);
118 ReleaseSRWLockExclusive(&deleg->lock);
119
120 /* release the client's reference */
122}
VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable)
Definition: sync.c:137

Referenced by delegation_return(), and nfs41_client_delegation_recovery().

◆ delegation_return()

static int delegation_return ( IN nfs41_client client,
IN nfs41_delegation_state deleg,
IN bool_t  truncate,
IN bool_t  try_recovery 
)
static

Definition at line 264 of file delegation.c.

269{
270 stateid_arg stateid;
272 int status;
273
274 if (deleg->srv_open) {
275 /* make an upcall to the kernel: invalide data cache */
276 HANDLE pipe;
277 unsigned char inbuf[sizeof(HANDLE)], *buffer = inbuf;
278 DWORD inbuf_len = sizeof(HANDLE), outbuf_len, dstatus;
280 dprintf(1, "delegation_return: making a downcall for srv_open=%x\n",
281 deleg->srv_open);
284 if (pipe == INVALID_HANDLE_VALUE) {
285 eprintf("delegation_return: Unable to open downcall pipe %d\n",
286 GetLastError());
287 goto out_downcall;
288 }
289 length = inbuf_len;
290 safe_write(&buffer, &length, &deleg->srv_open, sizeof(HANDLE));
291
292 dstatus = DeviceIoControl(pipe, IOCTL_NFS41_INVALCACHE, inbuf, inbuf_len,
293 NULL, 0, (LPDWORD)&outbuf_len, NULL);
294 if (!dstatus)
295 eprintf("IOCTL_NFS41_INVALCACHE failed %d\n", GetLastError());
296 CloseHandle(pipe);
297 }
298out_downcall:
299
300 /* recover opens and locks associated with the delegation */
301 while (open = deleg_open_find(&client->state, deleg)) {
302 status = nfs41_delegation_to_open(open, try_recovery);
303 if (status == NFS4_OK)
304 status = delegation_flush_locks(open, try_recovery);
306
307 if (status)
308 break;
309 }
310
311 /* return the delegation */
312 stateid.type = STATEID_DELEG_FILE;
313 stateid.open = NULL;
314 stateid.delegation = deleg;
315 AcquireSRWLockShared(&deleg->lock);
316 memcpy(&stateid.stateid, &deleg->state.stateid, sizeof(stateid4));
317 ReleaseSRWLockShared(&deleg->lock);
318
320 &deleg->file, &stateid, try_recovery);
322 goto out;
323
325out:
326 return status;
327}
static int inbuf
Definition: adnsresfilter.c:73
int safe_write(unsigned char **pos, uint32_t *remaining, void *src, uint32_t src_len)
Definition: util.c:44
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
static nfs41_open_state * deleg_open_find(IN struct client_state *state, IN const nfs41_delegation_state *deleg)
Definition: delegation.c:155
static int delegation_flush_locks(IN nfs41_open_state *open, IN bool_t try_recovery)
Definition: delegation.c:215
int nfs41_delegation_to_open(IN nfs41_open_state *open, IN bool_t try_recovery)
Definition: delegation.c:539
static void delegation_remove(IN nfs41_client *client, IN nfs41_delegation_state *deleg)
Definition: delegation.c:91
BOOL WINAPI DeviceIoControl(IN HANDLE hDevice, IN DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL, IN DWORD nInBufferSize OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL, IN DWORD nOutBufferSize OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: deviceio.c:136
UINT32 uint32_t
Definition: types.h:75
#define CloseHandle
Definition: compat.h:739
#define OPEN_EXISTING
Definition: compat.h:775
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GENERIC_READ
Definition: compat.h:135
#define FILE_SHARE_READ
Definition: compat.h:136
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint buffer
Definition: glext.h:5915
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
void nfs41_open_state_deref(IN nfs41_open_state *state)
Definition: open.c:104
@ NFS4ERR_BADSESSION
Definition: nfs41_const.h:161
#define IOCTL_NFS41_INVALCACHE
Definition: nfs41_driver.h:50
#define NFS41_USER_DEVICE_NAME_A
Definition: nfs41_driver.h:28
int nfs41_delegreturn(IN nfs41_session *session, IN nfs41_path_fh *file, IN stateid_arg *stateid, IN bool_t try_recovery)
Definition: nfs41_ops.c:1693
@ STATEID_DELEG_FILE
Definition: nfs41_ops.h:278
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define GENERIC_WRITE
Definition: nt_native.h:90
#define dprintf
Definition: regdump.c:33
PVOID HANDLE
Definition: typedefs.h:73
uint32_t * LPDWORD
Definition: typedefs.h:59
#define CreateFile
Definition: winbase.h:3749

Referenced by delegation_recall_thread(), nfs41_client_delegation_recovery(), nfs41_client_delegation_return_lru(), nfs41_delegate_open(), and nfs41_delegation_return().

◆ delegation_truncate()

static int delegation_truncate ( IN nfs41_delegation_state deleg,
IN nfs41_client client,
IN stateid_arg stateid,
IN nfs41_file_info info 
)
static

Definition at line 440 of file delegation.c.

445{
446 nfs41_superblock *superblock = deleg->file.fh.superblock;
447
448 /* use SETATTR to truncate the file */
449 info->attrmask.arr[1] |= FATTR4_WORD1_TIME_CREATE |
451
452 get_nfs_time(&info->time_create);
453 get_nfs_time(&info->time_modify);
454 info->time_delta = &superblock->time_delta;
455
456 /* mask out unsupported attributes */
458
459 return nfs41_setattr(client->session, &deleg->file, stateid, info);
460}
void get_nfs_time(OUT nfstime4 *nfs_time)
Definition: util.c:210
static __inline void nfs41_superblock_supported_attrs(IN const nfs41_superblock *superblock, IN OUT bitmap4 *attrs)
Definition: nfs41.h:454
@ FATTR4_WORD1_TIME_CREATE
Definition: nfs41_const.h:262
@ FATTR4_WORD1_TIME_MODIFY_SET
Definition: nfs41_const.h:266
int nfs41_setattr(IN nfs41_session *session, IN nfs41_path_fh *file, IN stateid_arg *stateid, IN nfs41_file_info *info)
Definition: nfs41_ops.c:1351

Referenced by nfs41_delegate_open().

◆ has_delegated_locks()

static bool_t has_delegated_locks ( IN nfs41_open_state open)
static

Definition at line 128 of file delegation.c.

130{
131 struct list_entry *entry;
132 list_for_each(entry, &open->locks.list) {
133 if (lock_entry(entry)->delegated)
134 return TRUE;
135 }
136 return FALSE;
137}

Referenced by open_deleg_cmp().

◆ nfs41_client_delegation_free()

void nfs41_client_delegation_free ( IN nfs41_client client)

Definition at line 828 of file delegation.c.

830{
831 struct list_entry *entry, *tmp;
832
833 EnterCriticalSection(&client->state.lock);
834 list_for_each_tmp (entry, tmp, &client->state.delegations) {
837 }
838 LeaveCriticalSection(&client->state.lock);
839}
#define list_for_each_tmp(entry, tmp, head)
Definition: list.h:39

Referenced by nfs41_client_free().

◆ nfs41_client_delegation_recovery()

int nfs41_client_delegation_recovery ( IN nfs41_client client)

Definition at line 861 of file delegation.c.

863{
864 struct list_entry *entry, *tmp;
866 int status = NFS4_OK;
867
868 list_for_each_tmp(entry, tmp, &client->state.delegations) {
870
872 switch (status) {
874 /* the delegation was reclaimed, but flagged as recalled;
875 * return it with try_recovery=FALSE */
877 break;
878
880 /* reclaim failed, so we have no delegation state on the server;
881 * 'forget' the delegation without trying to return it */
883 status = NFS4_OK;
884 break;
885 }
886
888 goto out;
889 }
890
891 /* use DELEGPURGE to indicate that we're done reclaiming delegations */
892 status = nfs41_delegpurge(client->session);
893
894 /* support for DELEGPURGE is optional; ignore any errors but BADSESSION */
896 status = NFS4_OK;
897out:
898 return status;
899}
#define list_container(entry, type, field)
Definition: list.h:33
static int delegation_recovery_status(IN nfs41_delegation_state *deleg)
Definition: delegation.c:842
#define client_entry(pos)
Definition: namespace.c:33
int nfs41_delegpurge(IN nfs41_session *session)
Definition: nfs41_ops.c:1666

Referenced by nfs41_client_state_revoked(), and nfs41_recover_client_state().

◆ nfs41_client_delegation_return_lru()

int nfs41_client_delegation_return_lru ( IN nfs41_client client)

Definition at line 902 of file delegation.c.

904{
905 struct list_entry *entry;
908
909 /* starting from the least recently opened, find and return
910 * the first delegation that's not 'in use' (currently open) */
911
912 /* TODO: use a more robust algorithm, taking into account:
913 * -number of total opens
914 * -time since last operation on an associated open, or
915 * -number of operations/second over last n seconds */
916 EnterCriticalSection(&client->state.lock);
917 list_for_each(entry, &client->state.delegations) {
919
920 /* skip if it's currently in use for an open; note that ref_count
921 * can't go from 1 to 2 without holding client->state.lock */
922 if (state->ref_count > 1)
923 continue;
924
926 if (state->status == DELEGATION_GRANTED) {
927 /* start returning the delegation */
928 state->status = DELEGATION_RETURNING;
930 }
932
934 break;
935 }
936 LeaveCriticalSection(&client->state.lock);
937
940 return status;
941}

Referenced by open_update_cache().

◆ nfs41_delegate_open()

int nfs41_delegate_open ( IN nfs41_open_state state,
IN uint32_t  create,
IN OPTIONAL nfs41_file_info createattrs,
OUT nfs41_file_info info 
)

Definition at line 462 of file delegation.c.

467{
468 nfs41_client *client = state->session->client;
469 nfs41_path_fh *file = &state->file;
470 uint32_t access = state->share_access;
471 uint32_t deny = state->share_deny;
473 stateid_arg stateid;
474 int status;
475
476 /* search for a delegation with this filehandle */
478 if (status)
479 goto out;
480
482 if (deleg->status != DELEGATION_GRANTED) {
483 /* the delegation is being returned, wait for it to finish */
484 while (deleg->status != DELEGATION_RETURNED)
485 SleepConditionVariableSRW(&deleg->cond, &deleg->lock, INFINITE, 0);
487 }
488 else if (!delegation_compatible(deleg->state.type, create, access, deny)) {
489#ifdef DELEGATION_RETURN_ON_CONFLICT
490 /* this open will conflict, start the delegation return */
493#else
495#endif
496 } else if (create == OPEN4_CREATE) {
497 /* copy the stateid for SETATTR */
498 stateid.open = NULL;
499 stateid.delegation = deleg;
500 stateid.type = STATEID_DELEG_FILE;
501 memcpy(&stateid.stateid, &deleg->state.stateid, sizeof(stateid4));
502 }
503 if (!status) {
504 dprintf(1, "nfs41_delegate_open: updating srv_open from %x to %x\n",
505 deleg->srv_open, state->srv_open);
506 deleg->srv_open = state->srv_open;
507 }
509
511 goto out_return;
512 if (status)
513 goto out_deleg;
514
515 if (create == OPEN4_CREATE) {
516 memcpy(info, createattrs, sizeof(nfs41_file_info));
517
518 /* write delegations allow us to simulate OPEN4_CREATE with SETATTR */
519 status = delegation_truncate(deleg, client, &stateid, info);
520 if (status)
521 goto out_deleg;
522 }
523
524 /* TODO: check access against deleg->state.permissions or send ACCESS */
525
526 state->delegation.state = deleg;
527 status = NFS4_OK;
528out:
529 return status;
530
531out_return:
533
534out_deleg:
536 goto out;
537}
static int deleg_file_cmp(const struct list_entry *entry, const void *value)
Definition: delegation.c:379
static int delegation_truncate(IN nfs41_delegation_state *deleg, IN nfs41_client *client, IN stateid_arg *stateid, IN nfs41_file_info *info)
Definition: delegation.c:440
static bool_t delegation_compatible(IN enum open_delegation_type4 type, IN uint32_t create, IN uint32_t access, IN uint32_t deny)
Definition: delegation.c:388
static int delegation_find(IN nfs41_client *client, IN const void *value, IN list_compare_fn cmp, OUT nfs41_delegation_state **deleg_out)
Definition: delegation.c:415
BOOL WINAPI SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable, PSRWLOCK Lock, DWORD Timeout, ULONG Flags)
Definition: sync.c:121
#define INFINITE
Definition: serial.h:102
enum delegation_status status
Definition: nfs41.h:103
open_delegation4 state
Definition: nfs41.h:96
CONDITION_VARIABLE cond
Definition: nfs41.h:105
enum open_delegation_type4 type
Definition: nfs41_types.h:154

Referenced by open_or_delegate().

◆ nfs41_delegation_deref()

void nfs41_delegation_deref ( IN nfs41_delegation_state state)

Definition at line 79 of file delegation.c.

81{
82 const LONG count = InterlockedDecrement(&state->ref_count);
83 dprintf(DGLVL, "nfs41_delegation_deref(%s) count %d\n",
84 state->path.path, count);
85 if (count == 0)
86 free(state);
87}
#define InterlockedDecrement
Definition: armddk.h:52
#define DGLVL
Definition: delegation.c:32
GLuint GLuint GLsizei count
Definition: gl.h:1545
long LONG
Definition: pedump.c:60

Referenced by delegation_recall_thread(), delegation_remove(), nfs41_client_delegation_free(), nfs41_delegate_open(), nfs41_delegation_getattr(), nfs41_delegation_recall(), nfs41_delegation_remove_srvopen(), nfs41_delegation_return(), and open_state_free().

◆ nfs41_delegation_getattr()

int nfs41_delegation_getattr ( IN nfs41_client client,
IN const nfs41_fh fh,
IN const bitmap4 attr_request,
OUT nfs41_file_info info 
)

Definition at line 783 of file delegation.c.

788{
790 uint64_t fileid;
791 int status;
792
793 dprintf(2, "--> nfs41_delegation_getattr()\n");
794
795 /* search for a delegation on this file handle */
797 if (status)
798 goto out;
799
800 AcquireSRWLockShared(&deleg->lock);
801 fileid = deleg->file.fh.fileid;
802 if (deleg->status != DELEGATION_GRANTED ||
803 deleg->state.type != OPEN_DELEGATE_WRITE) {
805 }
806 ReleaseSRWLockShared(&deleg->lock);
807 if (status)
808 goto out_deleg;
809
811
812 /* find attributes for the given fileid */
814 client_name_cache(client), fileid, info);
815 if (status) {
817 goto out_deleg;
818 }
819out_deleg:
821out:
822 dprintf(DGLVL, "<-- nfs41_delegation_getattr() returning %s\n",
824 return status;
825}
const char * nfs_error_string(int status)
Definition: daemon_debug.c:370
static int deleg_fh_cmp(const struct list_entry *entry, const void *value)
Definition: delegation.c:775
UINT64 uint64_t
Definition: types.h:77
int nfs41_attr_cache_lookup(IN struct nfs41_name_cache *cache, IN uint64_t fileid, OUT nfs41_file_info *info_out)
Definition: name_cache.c:859
static __inline struct nfs41_name_cache * client_name_cache(IN nfs41_client *client)
Definition: name_cache.h:28
nfs41_path_fh file
Definition: nfs41.h:99
#define ZeroMemory
Definition: winbase.h:1712

Referenced by handle_cb_getattr().

◆ nfs41_delegation_granted()

int nfs41_delegation_granted ( IN nfs41_session session,
IN nfs41_path_fh parent,
IN nfs41_path_fh file,
IN open_delegation4 delegation,
IN bool_t  try_recovery,
OUT nfs41_delegation_state **  deleg_out 
)

Definition at line 330 of file delegation.c.

337{
338 stateid_arg stateid;
339 nfs41_client *client = session->client;
341 int status = NO_ERROR;
342
343 if (delegation->type != OPEN_DELEGATE_READ &&
344 delegation->type != OPEN_DELEGATE_WRITE)
345 goto out;
346
347 if (delegation->recalled) {
349 goto out_return;
350 }
351
352 /* allocate the delegation state */
353 status = delegation_create(parent, file, delegation, &state);
354 if (status)
355 goto out_return;
356
357 /* register the delegation with the client */
358 EnterCriticalSection(&client->state.lock);
359 /* XXX: check for duplicates by fh and stateid? */
360 list_add_tail(&client->state.delegations, &state->client_entry);
361 LeaveCriticalSection(&client->state.lock);
362
363 nfs41_delegation_ref(state); /* return a reference */
364 *deleg_out = state;
365out:
366 return status;
367
368out_return: /* return the delegation on failure */
369 memcpy(&stateid.stateid, &delegation->stateid, sizeof(stateid4));
370 stateid.type = STATEID_DELEG_FILE;
371 stateid.open = NULL;
372 stateid.delegation = NULL;
373 nfs41_delegreturn(session, file, &stateid, try_recovery);
374 goto out;
375}
static int delegation_create(IN const nfs41_path_fh *parent, IN const nfs41_path_fh *file, IN const open_delegation4 *delegation, OUT nfs41_delegation_state **deleg_out)
Definition: delegation.c:36

Referenced by do_open(), and recover_open().

◆ nfs41_delegation_recall()

int nfs41_delegation_recall ( IN nfs41_client client,
IN nfs41_fh fh,
IN const stateid4 stateid,
IN bool_t  truncate 
)

Definition at line 703 of file delegation.c.

708{
710 struct recall_thread_args *args;
711 int status;
712
713 dprintf(2, "--> nfs41_delegation_recall()\n");
714
715 /* search for the delegation by stateid instead of filehandle;
716 * deleg_file_cmp() relies on a proper superblock and fileid,
717 * which we don't get with CB_RECALL */
718 status = delegation_find(client, stateid, deleg_stateid_cmp, &deleg);
719 if (status)
720 goto out;
721
723 if (deleg->state.recalled) {
724 /* return BADHANDLE if we've already responded to CB_RECALL */
726 } else {
727 deleg->state.recalled = 1;
728
729 if (deleg->status == DELEGATION_GRANTED) {
730 /* start the delegation return */
733 } /* else return NFS4_OK */
734 }
736
738 goto out_deleg;
739
740 /* allocate thread arguments */
741 args = calloc(1, sizeof(struct recall_thread_args));
742 if (args == NULL) {
744 eprintf("nfs41_delegation_recall() failed to allocate arguments\n");
745 goto out_deleg;
746 }
747
748 /* hold a reference on the root */
749 nfs41_root_ref(client->root);
750 args->client = client;
751 args->delegation = deleg;
752 args->truncate = truncate;
753
754 /* the callback thread can't make rpc calls, so spawn a separate thread */
757 eprintf("nfs41_delegation_recall() failed to start thread\n");
758 goto out_args;
759 }
760 status = NFS4_OK;
761out:
762 dprintf(DGLVL, "<-- nfs41_delegation_recall() returning %s\n",
764 return status;
765
766out_args:
767 free(args);
769out_deleg:
771 goto out;
772}
static int deleg_stateid_cmp(const struct list_entry *entry, const void *value)
Definition: delegation.c:696
static unsigned int WINAPI delegation_recall_thread(void *args)
Definition: delegation.c:683
void nfs41_root_ref(IN nfs41_root *root)
Definition: namespace.c:92
@ NFS4ERR_SERVERFAULT
Definition: nfs41_const.h:111
_CRTIMP uintptr_t __cdecl _beginthreadex(_In_opt_ void *_Security, _In_ unsigned _StackSize, _In_ unsigned(__stdcall *_StartAddress)(void *), _In_opt_ void *_ArgList, _In_ unsigned _InitFlag, _Out_opt_ unsigned *_ThrdAddr)
#define args
Definition: format.c:66

Referenced by handle_cb_recall().

◆ nfs41_delegation_ref()

void nfs41_delegation_ref ( IN nfs41_delegation_state state)

Definition at line 71 of file delegation.c.

73{
74 const LONG count = InterlockedIncrement(&state->ref_count);
75 dprintf(DGLVL, "nfs41_delegation_ref(%s) count %d\n",
76 state->path.path, count);
77}
#define InterlockedIncrement
Definition: armddk.h:53

Referenced by delegation_find(), and nfs41_delegation_granted().

◆ nfs41_delegation_remove_srvopen()

void nfs41_delegation_remove_srvopen ( IN nfs41_session session,
IN nfs41_path_fh file 
)

Definition at line 610 of file delegation.c.

613{
615
616 /* find a delegation for this file */
617 if (delegation_find(session->client, &file->fh, deleg_file_cmp, &deleg))
618 return;
619 dprintf(1, "nfs41_delegation_remove_srvopen: removing reference to "
620 "srv_open=%x\n", deleg->srv_open);
622 deleg->srv_open = NULL;
625}

Referenced by handle_close().

◆ nfs41_delegation_return()

int nfs41_delegation_return ( IN nfs41_session session,
IN nfs41_path_fh file,
IN enum open_delegation_type4  access,
IN bool_t  truncate 
)

Definition at line 629 of file delegation.c.

638{
639 nfs41_client *client = session->client;
641 int status;
642
643 /* find a delegation for this file */
645 if (status)
646 goto out;
647
649 if (deleg->status == DELEGATION_GRANTED) {
650 /* return unless delegation is write and access is read */
651 if (deleg->state.type != OPEN_DELEGATE_WRITE
655 }
656 } else {
657 /* the delegation is being returned, wait for it to finish */
658 while (deleg->status == DELEGATION_RETURNING)
659 SleepConditionVariableSRW(&deleg->cond, &deleg->lock, INFINITE, 0);
661 }
663
665 delegation_return(client, deleg, truncate, TRUE);
666 status = NFS4_OK;
667 }
668
670out:
671 return status;
672}

Referenced by cancel_open(), handle_close(), handle_nfs41_remove(), handle_nfs41_set_size(), handle_open(), handle_setacl(), and handle_setexattr().

◆ nfs41_delegation_to_open()

int nfs41_delegation_to_open ( IN nfs41_open_state open,
IN bool_t  try_recovery 
)

Definition at line 539 of file delegation.c.

542{
543 open_delegation4 ignore;
544 open_claim4 claim;
545 stateid4 open_stateid = { 0 };
546 stateid_arg deleg_stateid;
547 int status = NFS4_OK;
548
550 if (open->delegation.state == NULL) /* no delegation to reclaim */
551 goto out_unlock;
552
553 if (open->do_close) /* already have an open stateid */
554 goto out_unlock;
555
556 /* if another thread is reclaiming the open stateid,
557 * wait for it to finish before returning success */
558 if (open->delegation.reclaim) {
559 do {
560 SleepConditionVariableSRW(&open->delegation.cond, &open->lock,
561 INFINITE, 0);
562 } while (open->delegation.reclaim);
563 if (open->do_close)
564 goto out_unlock;
565 }
566 open->delegation.reclaim = 1;
567
568 AcquireSRWLockShared(&open->delegation.state->lock);
569 deleg_stateid.open = open;
570 deleg_stateid.delegation = NULL;
571 deleg_stateid.type = STATEID_DELEG_FILE;
572 memcpy(&deleg_stateid.stateid, &open->delegation.state->state.stateid,
573 sizeof(stateid4));
574 ReleaseSRWLockShared(&open->delegation.state->lock);
575
577
578 /* send OPEN with CLAIM_DELEGATE_CUR */
580 claim.u.deleg_cur.delegate_stateid = &deleg_stateid;
581 claim.u.deleg_cur.name = &open->file.name;
582
583 status = nfs41_open(open->session, &open->parent, &open->file,
584 &open->owner, &claim, open->share_access, open->share_deny,
585 OPEN4_NOCREATE, 0, NULL, try_recovery, &open_stateid, &ignore, NULL);
586
588 if (status == NFS4_OK) {
589 /* save the new open stateid */
590 memcpy(&open->stateid, &open_stateid, sizeof(stateid4));
591 open->do_close = 1;
592 } else if (open->do_close && (status == NFS4ERR_BAD_STATEID ||
594 /* something triggered client state recovery, and the open stateid
595 * has already been reclaimed; see recover_stateid_delegation() */
596 status = NFS4_OK;
597 }
598 open->delegation.reclaim = 0;
599
600 /* signal anyone waiting on the open stateid */
601 WakeAllConditionVariable(&open->delegation.cond);
602out_unlock:
604 if (status)
605 eprintf("nfs41_delegation_to_open(%p) failed with %s\n",
607 return status;
608}
@ NFS4ERR_BAD_STATEID
Definition: nfs41_const.h:132
@ NFS4ERR_EXPIRED
Definition: nfs41_const.h:116
@ NFS4ERR_STALE_STATEID
Definition: nfs41_const.h:130
int nfs41_open(IN nfs41_session *session, IN nfs41_path_fh *parent, IN nfs41_path_fh *file, IN state_owner4 *owner, IN open_claim4 *claim, IN uint32_t allow, IN uint32_t deny, IN uint32_t create, IN uint32_t how_mode, IN OPTIONAL nfs41_file_info *createattrs, IN bool_t try_recovery, OUT stateid4 *stateid, OUT open_delegation4 *delegation, OUT OPTIONAL nfs41_file_info *info)
Definition: nfs41_ops.c:366
@ OPEN4_NOCREATE
Definition: nfs41_ops.h:553
@ CLAIM_DELEGATE_CUR
Definition: nfs41_ops.h:595
struct __open_claim4::@50::__open_claim_deleg_cur deleg_cur
uint32_t claim
Definition: nfs41_ops.h:615
union __open_claim4::@50 u
char * name
Definition: compiler.c:66

Referenced by delegation_return(), and handle_lock().

◆ open_deleg_cmp()

static int open_deleg_cmp ( const struct list_entry entry,
const void value 
)
static

Definition at line 139 of file delegation.c.

140{
142 int result = -1;
143
144 /* open must match the delegation and have state to reclaim */
146 if (open->delegation.state != value) goto out;
147 if (open->do_close && !has_delegated_locks(open)) goto out;
148 result = 0;
149out:
151 return result;
152}
static bool_t has_delegated_locks(IN nfs41_open_state *open)
Definition: delegation.c:128
GLuint64EXT * result
Definition: glext.h:11304

Referenced by deleg_open_find().