ReactOS  0.4.12-dev-57-g7050ac4
name_cache.c
Go to the documentation of this file.
1 /* NFSv4.1 client for Windows
2  * Copyright 2012 The Regents of the University of Michigan
3  *
4  * Olga Kornievskaia <aglo@umich.edu>
5  * Casey Bodley <cbodley@umich.edu>
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or (at
10  * your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * without any warranty; without even the implied warranty of merchantability
14  * or fitness for a particular purpose. See the GNU Lesser General Public
15  * License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  */
21 
22 #include <windows.h>
23 #include <strsafe.h>
24 #include <time.h>
25 #include <assert.h>
26 
27 #include "nfs41_ops.h"
28 #include "nfs41_compound.h"
29 #include "name_cache.h"
30 #include "util.h"
31 #include "tree.h"
32 #include "daemon_debug.h"
33 
34 
35 /* dprintf levels for name cache logging */
36 enum {
37  NCLVL1 = 2,
39 };
40 
41 
42 #define NAME_CACHE_EXPIRATION 20 /* TODO: get from configuration */
43 
44 /* allow up to 256K of memory for name and attribute cache entries */
45 #define NAME_CACHE_MAX_SIZE 262144
46 
47 /* negative lookup caching
48  *
49  * by caching lookups that result in NOENT, we can avoid sending subsequent
50  * lookups over the wire. a name cache entry is negative when its attributes
51  * pointer is NULL. negative entries are created by three functions:
52  * nfs41_name_cache_remove(), _insert() when called with NULL for the fh and
53  * attributes, and _rename() for the source entry */
54 
55 /* delegations and cache feedback
56  *
57  * delegations provide a guarantee that no links or attributes will change
58  * without notice. the name cache takes advantage of this by preventing
59  * delegated entries from being removed on NAME_CACHE_EXPIRATION, though
60  * they're still removed when a parent is invalidated. the attribute cache
61  * holds an extra reference on delegated entries to prevent their removal
62  * entirely, until the delegation is returned.
63  * this extra reference presents a problem when the number of delegations
64  * approaches the maximum number of attribute cache entries. when there are
65  * not enough available entries to store the parent directories, every lookup
66  * results in a name cache miss, and cache performance degrades significantly.
67  * the solution is to provide feedback via nfs41_name_cache_insert() when
68  * delegations reach a certain percent of the cache capacity. the error code
69  * ERROR_TOO_MANY_OPEN_FILES, chosen arbitrarily for this case, instructs the
70  * caller to return an outstanding delegation before caching a new one.
71  */
72 static __inline bool_t is_delegation(
74 {
75  return type == OPEN_DELEGATE_READ || type == OPEN_DELEGATE_WRITE;
76 }
77 
78 
79 /* attribute cache */
81  RB_ENTRY(attr_cache_entry) rbnode;
82  struct list_entry free_entry;
83  uint64_t change;
84  uint64_t size;
85  uint64_t fileid;
86  int64_t time_access_s;
87  int64_t time_create_s;
88  int64_t time_modify_s;
89  uint32_t time_access_ns;
90  uint32_t time_create_ns;
91  uint32_t time_modify_ns;
92  uint32_t numlinks;
93  unsigned mode : 30;
94  unsigned hidden : 1;
95  unsigned system : 1;
96  unsigned archive : 1;
97  time_t expiration;
98  unsigned ref_count : 26;
99  unsigned type : 4;
100  unsigned invalidated : 1;
101  unsigned delegated : 1;
102 };
103 #define ATTR_ENTRY_SIZE sizeof(struct attr_cache_entry)
104 
105 RB_HEAD(attr_tree, attr_cache_entry);
106 
107 struct attr_cache {
108  struct attr_tree head;
111 };
112 
113 int attr_cmp(struct attr_cache_entry *lhs, struct attr_cache_entry *rhs)
114 {
115  return lhs->fileid < rhs->fileid ? -1 : lhs->fileid > rhs->fileid;
116 }
117 RB_GENERATE(attr_tree, attr_cache_entry, rbnode, attr_cmp)
118 
119 
120 /* attr_cache_entry */
121 #define attr_entry(pos) list_container(pos, struct attr_cache_entry, free_entry)
122 
124  IN struct attr_cache *cache,
125  IN uint64_t fileid,
126  OUT struct attr_cache_entry **entry_out)
127 {
128  struct attr_cache_entry *entry;
129  int status = NO_ERROR;
130 
131  /* get the next entry from free_entries and remove it */
132  if (list_empty(&cache->free_entries)) {
133  status = ERROR_OUTOFMEMORY;
134  goto out;
135  }
136  entry = attr_entry(cache->free_entries.next);
137  list_remove(&entry->free_entry);
138 
139  entry->fileid = fileid;
140  entry->invalidated = FALSE;
141  entry->delegated = FALSE;
142  *entry_out = entry;
143 out:
144  return status;
145 }
146 
147 static __inline void attr_cache_entry_free(
148  IN struct attr_cache *cache,
149  IN struct attr_cache_entry *entry)
150 {
151  dprintf(NCLVL1, "attr_cache_entry_free(%llu)\n", entry->fileid);
152  RB_REMOVE(attr_tree, &cache->head, entry);
153  /* add it back to free_entries */
154  list_add_tail(&cache->free_entries, &entry->free_entry);
155 }
156 
157 static __inline void attr_cache_entry_ref(
158  IN struct attr_cache *cache,
159  IN struct attr_cache_entry *entry)
160 {
161  const uint32_t previous = entry->ref_count++;
162  dprintf(NCLVL2, "attr_cache_entry_ref(%llu) %u -> %u\n",
163  entry->fileid, previous, entry->ref_count);
164 }
165 
166 static __inline void attr_cache_entry_deref(
167  IN struct attr_cache *cache,
168  IN struct attr_cache_entry *entry)
169 {
170  const uint32_t previous = entry->ref_count--;
171  dprintf(NCLVL2, "attr_cache_entry_deref(%llu) %u -> %u\n",
172  entry->fileid, previous, entry->ref_count);
173 
174  if (entry->ref_count == 0)
175  attr_cache_entry_free(cache, entry);
176 }
177 
178 static __inline int attr_cache_entry_expired(
179  IN const struct attr_cache_entry *entry)
180 {
181  return entry->invalidated ||
182  (!entry->delegated && time(NULL) > entry->expiration);
183 }
184 
185 /* attr_cache */
186 static int attr_cache_init(
187  IN struct attr_cache *cache,
188  IN uint32_t max_entries)
189 {
190  uint32_t i;
191  int status = NO_ERROR;
192 
193  /* allocate a pool of entries */
194  cache->pool = calloc(max_entries, ATTR_ENTRY_SIZE);
195  if (cache->pool == NULL) {
196  status = GetLastError();
197  goto out;
198  }
199 
200  /* initialize the list of free entries */
201  list_init(&cache->free_entries);
202  for (i = 0; i < max_entries; i++) {
203  list_init(&cache->pool[i].free_entry);
204  list_add_tail(&cache->free_entries, &cache->pool[i].free_entry);
205  }
206 out:
207  return status;
208 }
209 
210 static void attr_cache_free(
211  IN struct attr_cache *cache)
212 {
213  /* free the pool */
214  free(cache->pool);
215  cache->pool = NULL;
216  list_init(&cache->free_entries);
217 }
218 
220  IN struct attr_cache *cache,
221  IN uint64_t fileid)
222 {
223  /* find an entry that matches fileid */
224  struct attr_cache_entry tmp;
225  tmp.fileid = fileid;
226  return RB_FIND(attr_tree, &cache->head, &tmp);
227 }
228 
229 static int attr_cache_insert(
230  IN struct attr_cache *cache,
231  IN struct attr_cache_entry *entry)
232 {
233  int status = NO_ERROR;
234 
235  dprintf(NCLVL2, "--> attr_cache_insert(%llu)\n", entry->fileid);
236 
237  if (RB_INSERT(attr_tree, &cache->head, entry))
238  status = ERROR_FILE_EXISTS;
239 
240  dprintf(NCLVL2, "<-- attr_cache_insert() returning %d\n", status);
241  return status;
242 }
243 
245  IN struct attr_cache *cache,
246  IN uint64_t fileid,
247  OUT struct attr_cache_entry **entry_out)
248 {
249  struct attr_cache_entry *entry;
250  int status = NO_ERROR;
251 
252  dprintf(NCLVL1, "--> attr_cache_find_or_create(%llu)\n", fileid);
253 
254  /* look for an existing entry */
255  entry = attr_cache_search(cache, fileid);
256  if (entry == NULL) {
257  /* create and insert */
258  status = attr_cache_entry_create(cache, fileid, &entry);
259  if (status)
260  goto out;
261 
262  status = attr_cache_insert(cache, entry);
263  if (status)
264  goto out_err_free;
265  }
266 
267  /* take a reference on success */
268  attr_cache_entry_ref(cache, entry);
269 
270 out:
271  *entry_out = entry;
272  dprintf(NCLVL1, "<-- attr_cache_find_or_create() returning %d\n",
273  status);
274  return status;
275 
276 out_err_free:
277  attr_cache_entry_free(cache, entry);
278  entry = NULL;
279  goto out;
280 }
281 
282 static void attr_cache_update(
283  IN struct attr_cache_entry *entry,
284  IN const nfs41_file_info *info,
285  IN enum open_delegation_type4 delegation)
286 {
287  /* update the attributes present in mask */
288  if (info->attrmask.count >= 1) {
289  if (info->attrmask.arr[0] & FATTR4_WORD0_TYPE)
290  entry->type = (unsigned char)(info->type & NFS_FTYPE_MASK);
291  if (info->attrmask.arr[0] & FATTR4_WORD0_CHANGE) {
292  entry->change = info->change;
293  /* revalidate whenever we get a change attribute */
294  entry->invalidated = 0;
295  entry->expiration = time(NULL) + NAME_CACHE_EXPIRATION;
296  }
297  if (info->attrmask.arr[0] & FATTR4_WORD0_SIZE)
298  entry->size = info->size;
299  if (info->attrmask.arr[0] & FATTR4_WORD0_HIDDEN)
300  entry->hidden = info->hidden;
301  if (info->attrmask.arr[0] & FATTR4_WORD0_ARCHIVE)
302  entry->archive = info->archive;
303  }
304  if (info->attrmask.count >= 2) {
305  if (info->attrmask.arr[1] & FATTR4_WORD1_MODE)
306  entry->mode = info->mode;
307  if (info->attrmask.arr[1] & FATTR4_WORD1_NUMLINKS)
308  entry->numlinks = info->numlinks;
309  if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_ACCESS) {
310  entry->time_access_s = info->time_access.seconds;
311  entry->time_access_ns = info->time_access.nseconds;
312  }
313  if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_CREATE) {
314  entry->time_create_s = info->time_create.seconds;
315  entry->time_create_ns = info->time_create.nseconds;
316  }
317  if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_MODIFY) {
318  entry->time_modify_s = info->time_modify.seconds;
319  entry->time_modify_ns = info->time_modify.nseconds;
320  }
321  if (info->attrmask.arr[1] & FATTR4_WORD1_SYSTEM)
322  entry->system = info->system;
323  }
324 
325  if (is_delegation(delegation))
326  entry->delegated = TRUE;
327 }
328 
329 static void copy_attrs(
331  IN const struct attr_cache_entry *src)
332 {
333  dst->change = src->change;
334  dst->size = src->size;
335  dst->time_access.seconds = src->time_access_s;
336  dst->time_access.nseconds = src->time_access_ns;
337  dst->time_create.seconds = src->time_create_s;
338  dst->time_create.nseconds = src->time_create_ns;
339  dst->time_modify.seconds = src->time_modify_s;
340  dst->time_modify.nseconds = src->time_modify_ns;
341  dst->type = src->type;
342  dst->numlinks = src->numlinks;
343  dst->mode = src->mode;
344  dst->fileid = src->fileid;
345  dst->hidden = src->hidden;
346  dst->system = src->system;
347  dst->archive = src->archive;
348 
349  dst->attrmask.count = 2;
350  dst->attrmask.arr[0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE
353  dst->attrmask.arr[1] = FATTR4_WORD1_MODE
357 }
358 
359 
360 /* name cache */
361 RB_HEAD(name_tree, name_cache_entry);
363  char component[NFS41_MAX_COMPONENT_LEN];
365  RB_ENTRY(name_cache_entry) rbnode;
366  struct name_tree rbchildren;
367  struct attr_cache_entry *attributes;
368  struct name_cache_entry *parent;
369  struct list_entry exp_entry;
370  time_t expiration;
371  unsigned short component_len;
372 };
373 #define NAME_ENTRY_SIZE sizeof(struct name_cache_entry)
374 
375 int name_cmp(struct name_cache_entry *lhs, struct name_cache_entry *rhs)
376 {
377  const int diff = rhs->component_len - lhs->component_len;
378  return diff ? diff : strncmp(lhs->component, rhs->component, lhs->component_len);
379 }
380 RB_GENERATE(name_tree, name_cache_entry, rbnode, name_cmp)
381 
385  struct attr_cache attributes;
386  struct list_entry exp_entries; /* list of entries by expiry */
392  SRWLOCK lock;
393 };
394 
395 
396 /* internal name cache functions used by the public name cache interface;
397  * these functions expect the caller to hold a lock on the cache */
398 
399 #define name_entry(pos) list_container(pos, struct name_cache_entry, exp_entry)
400 
401 static __inline bool_t name_cache_enabled(
402  IN struct nfs41_name_cache *cache)
403 {
404  return cache->expiration > 0;
405 }
406 
407 static __inline void name_cache_entry_rename(
408  OUT struct name_cache_entry *entry,
409  IN const nfs41_component *component)
410 {
411  StringCchCopyNA(entry->component, NFS41_MAX_COMPONENT_LEN,
412  component->name, component->len);
413  entry->component_len = component->len;
414 }
415 
416 static __inline void name_cache_remove(
417  IN struct name_cache_entry *entry,
418  IN struct name_cache_entry *parent)
419 {
420  RB_REMOVE(name_tree, &parent->rbchildren, entry);
421  entry->parent = NULL;
422 }
423 
425  IN struct nfs41_name_cache *cache,
426  IN struct name_cache_entry *parent);
427 
428 static __inline void name_cache_unlink(
429  IN struct nfs41_name_cache *cache,
430  IN struct name_cache_entry *entry)
431 {
432  /* remove the entry from the tree */
433  if (entry->parent)
434  name_cache_remove(entry, entry->parent);
435  else if (entry == cache->root)
436  cache->root = NULL;
437 
438  /* unlink all of its children */
440  /* release the cached attributes */
441  if (entry->attributes) {
442  attr_cache_entry_deref(&cache->attributes, entry->attributes);
443  entry->attributes = NULL;
444  }
445  /* move it to the end of exp_entries for scavenging */
446  list_remove(&entry->exp_entry);
447  list_add_tail(&cache->exp_entries, &entry->exp_entry);
448 }
449 
451  IN struct nfs41_name_cache *cache,
452  IN struct name_cache_entry *parent)
453 {
454  struct name_cache_entry *entry, *tmp;
455  RB_FOREACH_SAFE(entry, name_tree, &parent->rbchildren, tmp)
456  name_cache_unlink(cache, entry);
457 }
458 
460  IN struct nfs41_name_cache *cache,
462  OUT struct name_cache_entry **entry_out)
463 {
464  int status = NO_ERROR;
465  struct name_cache_entry *entry;
466 
467  if (cache->entries >= cache->max_entries) {
468  /* scavenge the oldest entry */
469  if (list_empty(&cache->exp_entries)) {
470  status = ERROR_OUTOFMEMORY;
471  goto out;
472  }
473  entry = name_entry(cache->exp_entries.prev);
474  name_cache_unlink(cache, entry);
475 
476  dprintf(NCLVL2, "name_cache_entry_create('%s') scavenged 0x%p\n",
477  component->name, entry);
478  } else {
479  /* take the next entry in the pool and add it to exp_entries */
480  entry = &cache->pool[cache->entries++];
481  list_init(&entry->exp_entry);
482  list_add_tail(&cache->exp_entries, &entry->exp_entry);
483  }
484 
485  name_cache_entry_rename(entry, component);
486 
487  *entry_out = entry;
488 out:
489  return status;
490 }
491 
493  IN struct nfs41_name_cache *cache,
494  IN struct name_cache_entry *entry)
495 {
496  /* move the entry to the front of cache->exp_entries, then do
497  * the same for its parents, which are more costly to evict */
498  while (entry) {
499  /* if entry is delegated, it won't be in the list */
500  if (!list_empty(&entry->exp_entry)) {
501  list_remove(&entry->exp_entry);
502  list_add_head(&cache->exp_entries, &entry->exp_entry);
503  }
504  if (entry == entry->parent)
505  break;
506  entry = entry->parent;
507  }
508 }
509 
511  IN struct nfs41_name_cache *cache,
512  IN struct name_cache_entry *entry)
513 {
514  /* update the expiration timer */
515  entry->expiration = time(NULL) + cache->expiration;
516  name_cache_entry_accessed(cache, entry);
517 }
518 
520  IN struct nfs41_name_cache *cache,
521  IN struct name_cache_entry *entry,
522  IN OPTIONAL const nfs41_fh *fh,
524  IN enum open_delegation_type4 delegation)
525 {
526  int status = NO_ERROR;
527 
528  if (fh)
529  fh_copy(&entry->fh, fh);
530  else
531  entry->fh.len = 0;
532 
533  if (info) {
534  if (entry->attributes == NULL) {
535  /* negative -> positive entry, create the attributes */
536  status = attr_cache_find_or_create(&cache->attributes,
537  info->fileid, &entry->attributes);
538  if (status)
539  goto out;
540  }
541 
542  attr_cache_update(entry->attributes, info, delegation);
543 
544  /* hold a reference as long as we have the delegation */
545  if (is_delegation(delegation)) {
546  attr_cache_entry_ref(&cache->attributes, entry->attributes);
547  cache->delegations++;
548  }
549 
550  /* keep the entry from expiring */
551  if (entry->attributes->delegated)
552  list_remove(&entry->exp_entry);
553  } else if (entry->attributes) {
554  /* positive -> negative entry, deref the attributes */
555  attr_cache_entry_deref(&cache->attributes, entry->attributes);
556  entry->attributes = NULL;
557  }
558  name_cache_entry_updated(cache, entry);
559 out:
560  return status;
561 }
562 
564  IN struct nfs41_name_cache *cache,
565  IN struct name_cache_entry *entry,
566  IN const change_info4 *cinfo)
567 {
568  if (entry->attributes == NULL)
569  return FALSE;
570 
571  if (cinfo->after == entry->attributes->change ||
572  (cinfo->atomic && cinfo->before == entry->attributes->change)) {
573  entry->attributes->change = cinfo->after;
574  name_cache_entry_updated(cache, entry);
575  dprintf(NCLVL1, "name_cache_entry_changed('%s') has not changed. "
576  "updated change=%llu\n", entry->component,
577  entry->attributes->change);
578  return FALSE;
579  } else {
580  dprintf(NCLVL1, "name_cache_entry_changed('%s') has changed: was %llu, "
581  "got before=%llu\n", entry->component,
582  entry->attributes->change, cinfo->before);
583  return TRUE;
584  }
585 }
586 
588  IN struct nfs41_name_cache *cache,
589  IN struct name_cache_entry *entry)
590 {
591  dprintf(NCLVL1, "name_cache_entry_invalidate('%s')\n", entry->component);
592 
593  if (entry->attributes) {
594  /* flag attributes so that entry_invis() will return true
595  * if another entry attempts to use them */
596  entry->attributes->invalidated = 1;
597  }
598  name_cache_unlink(cache, entry);
599 }
600 
602  IN struct nfs41_name_cache *cache,
603  IN struct name_cache_entry *parent,
605 {
606  struct name_cache_entry tmp, *entry;
607 
608  dprintf(NCLVL2, "--> name_cache_search('%.*s' under '%s')\n",
609  component->len, component->name, parent->component);
610 
612  component->name, component->len);
613  tmp.component_len = component->len;
614 
615  entry = RB_FIND(name_tree, &parent->rbchildren, &tmp);
616  if (entry)
617  dprintf(NCLVL2, "<-- name_cache_search() "
618  "found existing entry 0x%p\n", entry);
619  else
620  dprintf(NCLVL2, "<-- name_cache_search() returning NULL\n");
621  return entry;
622 }
623 
624 static int entry_invis(
625  IN struct name_cache_entry *entry,
626  OUT OPTIONAL bool_t *is_negative)
627 {
628  /* name entry timer expired? */
629  if (!list_empty(&entry->exp_entry) && time(NULL) > entry->expiration) {
630  dprintf(NCLVL2, "name_entry_expired('%s')\n", entry->component);
631  return 1;
632  }
633  /* negative lookup entry? */
634  if (entry->attributes == NULL) {
635  if (is_negative) *is_negative = 1;
636  dprintf(NCLVL2, "name_entry_negative('%s')\n", entry->component);
637  return 1;
638  }
639  /* attribute entry expired? */
640  if (attr_cache_entry_expired(entry->attributes)) {
641  dprintf(NCLVL2, "attr_entry_expired(%llu)\n",
642  entry->attributes->fileid);
643  return 1;
644  }
645  return 0;
646 }
647 
648 static int name_cache_lookup(
649  IN struct nfs41_name_cache *cache,
650  IN bool_t skip_invis,
651  IN const char *path,
652  IN const char *path_end,
653  OUT OPTIONAL const char **remaining_path_out,
654  OUT OPTIONAL struct name_cache_entry **parent_out,
655  OUT OPTIONAL struct name_cache_entry **target_out,
656  OUT OPTIONAL bool_t *is_negative)
657 {
658  struct name_cache_entry *parent, *target;
660  const char *path_pos;
661  int status = NO_ERROR;
662 
663  dprintf(NCLVL1, "--> name_cache_lookup('%s')\n", path);
664 
665  parent = NULL;
666  target = cache->root;
667  component.name = path_pos = path;
668 
669  if (target == NULL || (skip_invis && entry_invis(target, is_negative))) {
670  target = NULL;
671  status = ERROR_PATH_NOT_FOUND;
672  goto out;
673  }
674 
675  while (next_component(path_pos, path_end, &component)) {
676  parent = target;
677  target = name_cache_search(cache, parent, &component);
678  path_pos = component.name + component.len;
679  if (target == NULL || (skip_invis && entry_invis(target, is_negative))) {
680  target = NULL;
681  if (is_last_component(component.name, path_end))
682  status = ERROR_FILE_NOT_FOUND;
683  else
684  status = ERROR_PATH_NOT_FOUND;
685  break;
686  }
687  }
688 out:
689  if (remaining_path_out) *remaining_path_out = component.name;
690  if (parent_out) *parent_out = parent;
691  if (target_out) *target_out = target;
692  dprintf(NCLVL1, "<-- name_cache_lookup() returning %d\n", status);
693  return status;
694 }
695 
696 static int name_cache_insert(
697  IN struct name_cache_entry *entry,
698  IN struct name_cache_entry *parent)
699 {
700  int status = NO_ERROR;
701 
702  dprintf(NCLVL2, "--> name_cache_insert('%s')\n", entry->component);
703 
704  if (RB_INSERT(name_tree, &parent->rbchildren, entry))
705  status = ERROR_FILE_EXISTS;
706  entry->parent = parent;
707 
708  dprintf(NCLVL2, "<-- name_cache_insert() returning %u\n", status);
709  return status;
710 }
711 
713  IN struct nfs41_name_cache *cache,
714  IN struct name_cache_entry *parent,
716  OUT struct name_cache_entry **target_out)
717 {
718  int status = NO_ERROR;
719 
720  dprintf(NCLVL1, "--> name_cache_find_or_create('%.*s' under '%s')\n",
721  component->len, component->name, parent->component);
722 
723  *target_out = name_cache_search(cache, parent, component);
724  if (*target_out)
725  goto out;
726 
727  status = name_cache_entry_create(cache, component, target_out);
728  if (status)
729  goto out;
730 
731  status = name_cache_insert(*target_out, parent);
732  if (status)
733  goto out_err;
734 
735 out:
736  dprintf(NCLVL1, "<-- name_cache_find_or_create() returning %d\n",
737  status);
738  return status;
739 
740 out_err:
741  *target_out = NULL;
742  goto out;
743 }
744 
745 
746 /* public name cache interface, declared in name_cache.h */
747 
748 /* assuming no hard links, calculate how many entries will fit in the cache */
749 #define SIZE_PER_ENTRY (ATTR_ENTRY_SIZE + NAME_ENTRY_SIZE)
750 #define NAME_CACHE_MAX_ENTRIES (NAME_CACHE_MAX_SIZE / SIZE_PER_ENTRY)
751 
753  OUT struct nfs41_name_cache **cache_out)
754 {
755  struct nfs41_name_cache *cache;
756  int status = NO_ERROR;
757 
758  dprintf(NCLVL1, "nfs41_name_cache_create()\n");
759 
760  /* allocate the cache */
761  cache = calloc(1, sizeof(struct nfs41_name_cache));
762  if (cache == NULL) {
763  status = GetLastError();
764  goto out;
765  }
766 
767  list_init(&cache->exp_entries);
771  InitializeSRWLock(&cache->lock);
772 
773  /* allocate a pool of entries */
774  cache->pool = calloc(cache->max_entries, NAME_ENTRY_SIZE);
775  if (cache->pool == NULL) {
776  status = GetLastError();
777  goto out_err_cache;
778  }
779 
780  /* initialize the attribute cache */
781  status = attr_cache_init(&cache->attributes, cache->max_entries);
782  if (status)
783  goto out_err_pool;
784 
785  *cache_out = cache;
786 out:
787  return status;
788 
789 out_err_pool:
790  free(cache->pool);
791 out_err_cache:
792  free(cache);
793  goto out;
794 }
795 
797  IN struct nfs41_name_cache **cache_out)
798 {
799  struct nfs41_name_cache *cache = *cache_out;
800  int status = NO_ERROR;
801 
802  dprintf(NCLVL1, "nfs41_name_cache_free()\n");
803 
804  /* free the attribute cache */
805  attr_cache_free(&cache->attributes);
806 
807  /* free the name entry pool */
808  free(cache->pool);
809  free(cache);
810  *cache_out = NULL;
811  return status;
812 }
813 
814 static __inline void copy_fh(
815  OUT nfs41_fh *dst,
816  IN OPTIONAL const struct name_cache_entry *src)
817 {
818  if (src)
819  fh_copy(dst, &src->fh);
820  else
821  dst->len = 0;
822 }
823 
825  IN struct nfs41_name_cache *cache,
826  IN const char *path,
827  IN const char *path_end,
828  OUT OPTIONAL const char **remaining_path_out,
829  OUT OPTIONAL nfs41_fh *parent_out,
830  OUT OPTIONAL nfs41_fh *target_out,
831  OUT OPTIONAL nfs41_file_info *info_out,
832  OUT OPTIONAL bool_t *is_negative)
833 {
834  struct name_cache_entry *parent, *target;
835  const char *path_pos = path;
836  int status;
837 
838  AcquireSRWLockShared(&cache->lock);
839 
840  if (!name_cache_enabled(cache)) {
841  status = ERROR_NOT_SUPPORTED;
842  goto out_unlock;
843  }
844 
845  status = name_cache_lookup(cache, 1, path, path_end,
846  &path_pos, &parent, &target, is_negative);
847 
848  if (parent_out) copy_fh(parent_out, parent);
849  if (target_out) copy_fh(target_out, target);
850  if (info_out && target && target->attributes)
851  copy_attrs(info_out, target->attributes);
852 
853 out_unlock:
854  ReleaseSRWLockShared(&cache->lock);
855  if (remaining_path_out) *remaining_path_out = path_pos;
856  return status;
857 }
858 
860  IN struct nfs41_name_cache *cache,
861  IN uint64_t fileid,
862  OUT nfs41_file_info *info_out)
863 {
864  struct attr_cache_entry *entry;
865  int status = NO_ERROR;
866 
867  dprintf(NCLVL1, "--> nfs41_attr_cache_lookup(%llu)\n", fileid);
868 
869  AcquireSRWLockShared(&cache->lock);
870 
871  if (!name_cache_enabled(cache)) {
872  status = ERROR_NOT_SUPPORTED;
873  goto out_unlock;
874  }
875 
876  entry = attr_cache_search(&cache->attributes, fileid);
877  if (entry == NULL || attr_cache_entry_expired(entry)) {
878  status = ERROR_FILE_NOT_FOUND;
879  goto out_unlock;
880  }
881 
882  copy_attrs(info_out, entry);
883 
884 out_unlock:
885  ReleaseSRWLockShared(&cache->lock);
886 
887  dprintf(NCLVL1, "<-- nfs41_attr_cache_lookup() returning %d\n", status);
888  return status;
889 }
890 
892  IN struct nfs41_name_cache *cache,
893  IN uint64_t fileid,
894  IN const nfs41_file_info *info)
895 {
896  struct attr_cache_entry *entry;
897  int status = NO_ERROR;
898 
899  dprintf(NCLVL1, "--> nfs41_attr_cache_update(%llu)\n", fileid);
900 
901  AcquireSRWLockExclusive(&cache->lock);
902 
903  if (!name_cache_enabled(cache)) {
904  status = ERROR_NOT_SUPPORTED;
905  goto out_unlock;
906  }
907 
908  entry = attr_cache_search(&cache->attributes, fileid);
909  if (entry == NULL) {
910  status = ERROR_FILE_NOT_FOUND;
911  goto out_unlock;
912  }
913 
915 
916 out_unlock:
917  ReleaseSRWLockExclusive(&cache->lock);
918 
919  dprintf(NCLVL1, "<-- nfs41_attr_cache_update() returning %d\n", status);
920  return status;
921 }
922 
924  IN struct nfs41_name_cache *cache,
925  IN const char *path,
926  IN const nfs41_component *name,
927  IN OPTIONAL const nfs41_fh *fh,
929  IN OPTIONAL const change_info4 *cinfo,
930  IN enum open_delegation_type4 delegation)
931 {
932  struct name_cache_entry *parent, *target;
933  int status;
934 
935  dprintf(NCLVL1, "--> nfs41_name_cache_insert('%.*s')\n",
936  name->name + name->len - path, path);
937 
938  AcquireSRWLockExclusive(&cache->lock);
939 
940  if (!name_cache_enabled(cache)) {
941  status = ERROR_NOT_SUPPORTED;
942  goto out_unlock;
943  }
944 
945  /* limit the number of delegations to prevent attr cache starvation */
946  if (is_delegation(delegation) &&
947  cache->delegations >= cache->max_delegations) {
948  status = ERROR_TOO_MANY_OPEN_FILES;
949  goto out_unlock;
950  }
951 
952  /* an empty path or component implies the root entry */
953  if (path == NULL || name == NULL || name->len == 0) {
954  /* create the root entry if it doesn't exist */
955  if (cache->root == NULL) {
956  const nfs41_component name = { "ROOT", 4 };
957  status = name_cache_entry_create(cache, &name, &cache->root);
958  if (status)
959  goto out_err_deleg;
960  }
961  target = cache->root;
962  } else {
963  /* find/create an entry under its parent */
964  status = name_cache_lookup(cache, 0, path,
965  name->name, NULL, NULL, &parent, NULL);
966  if (status)
967  goto out_err_deleg;
968 
969  if (cinfo && name_cache_entry_changed(cache, parent, cinfo)) {
970  name_cache_entry_invalidate(cache, parent);
971  goto out_err_deleg;
972  }
973 
974  status = name_cache_find_or_create(cache, parent, name, &target);
975  if (status)
976  goto out_err_deleg;
977  }
978 
979  /* pass in the new fh/attributes */
980  status = name_cache_entry_update(cache, target, fh, info, delegation);
981  if (status)
982  goto out_err_update;
983 
984 out_unlock:
985  ReleaseSRWLockExclusive(&cache->lock);
986 
987  dprintf(NCLVL1, "<-- nfs41_name_cache_insert() returning %d\n",
988  status);
989  return status;
990 
991 out_err_update:
992  /* a failure in name_cache_entry_update() leaves a negative entry
993  * where there shouldn't be one; remove it from the cache */
994  name_cache_entry_invalidate(cache, target);
995 
996 out_err_deleg:
997  if (is_delegation(delegation)) {
998  /* we still need a reference to the attributes for the delegation */
999  struct attr_cache_entry *attributes;
1000  status = attr_cache_find_or_create(&cache->attributes,
1001  info->fileid, &attributes);
1002  if (status == NO_ERROR) {
1003  attr_cache_update(attributes, info, delegation);
1004  cache->delegations++;
1005  }
1006  else
1007  status = ERROR_TOO_MANY_OPEN_FILES;
1008  }
1009  goto out_unlock;
1010 }
1011 
1013  IN struct nfs41_name_cache *cache,
1014  IN uint64_t fileid,
1015  IN const char *path,
1016  IN const nfs41_component *name)
1017 {
1018  struct name_cache_entry *parent, *target;
1019  struct attr_cache_entry *attributes;
1020  int status;
1021 
1022  dprintf(NCLVL1, "--> nfs41_name_cache_delegreturn(%llu, '%s')\n",
1023  fileid, path);
1024 
1025  AcquireSRWLockExclusive(&cache->lock);
1026 
1027  if (!name_cache_enabled(cache)) {
1028  status = ERROR_NOT_SUPPORTED;
1029  goto out_unlock;
1030  }
1031 
1032  status = name_cache_lookup(cache, 0, path,
1033  name->name + name->len, NULL, &parent, &target, NULL);
1034  if (status == NO_ERROR) {
1035  /* put the name cache entry back on the exp_entries list */
1036  list_add_head(&cache->exp_entries, &target->exp_entry);
1037  name_cache_entry_updated(cache, target);
1038 
1039  attributes = target->attributes;
1040  } else {
1041  /* should still have an attr cache entry */
1042  attributes = attr_cache_search(&cache->attributes, fileid);
1043  }
1044 
1045  if (attributes == NULL) {
1046  status = ERROR_FILE_NOT_FOUND;
1047  goto out_unlock;
1048  }
1049 
1050  /* release the reference from name_cache_entry_update() */
1051  if (attributes->delegated) {
1052  attributes->delegated = FALSE;
1053  attr_cache_entry_deref(&cache->attributes, attributes);
1054  assert(cache->delegations > 0);
1055  cache->delegations--;
1056  }
1057  status = NO_ERROR;
1058 
1059 out_unlock:
1060  ReleaseSRWLockExclusive(&cache->lock);
1061 
1062  dprintf(NCLVL1, "<-- nfs41_name_cache_delegreturn() returning %d\n", status);
1063  return status;
1064 }
1065 
1067  IN struct nfs41_name_cache *cache,
1068  IN const char *path,
1069  IN const nfs41_component *name,
1070  IN uint64_t fileid,
1071  IN const change_info4 *cinfo)
1072 {
1073  struct name_cache_entry *parent, *target;
1074  struct attr_cache_entry *attributes = NULL;
1075  int status;
1076 
1077  dprintf(NCLVL1, "--> nfs41_name_cache_remove('%s')\n", path);
1078 
1079  AcquireSRWLockExclusive(&cache->lock);
1080 
1081  if (!name_cache_enabled(cache)) {
1082  status = ERROR_NOT_SUPPORTED;
1083  goto out_unlock;
1084  }
1085 
1086  status = name_cache_lookup(cache, 0, path,
1087  name->name + name->len, NULL, &parent, &target, NULL);
1088  if (status == ERROR_PATH_NOT_FOUND)
1089  goto out_attributes;
1090 
1091  if (cinfo && name_cache_entry_changed(cache, parent, cinfo)) {
1092  name_cache_entry_invalidate(cache, parent);
1093  goto out_attributes;
1094  }
1095 
1096  if (status == ERROR_FILE_NOT_FOUND)
1097  goto out_attributes;
1098 
1099  if (target->attributes)
1100  target->attributes->numlinks--;
1101 
1102  /* make this a negative entry and unlink children */
1104  name_cache_unlink_children_recursive(cache, target);
1105 
1106 out_unlock:
1107  ReleaseSRWLockExclusive(&cache->lock);
1108 
1109  dprintf(NCLVL1, "<-- nfs41_name_cache_remove() returning %d\n", status);
1110  return status;
1111 
1112 out_attributes:
1113  /* in the presence of other links, we need to update numlinks
1114  * regardless of a failure to find the target entry */
1115  dprintf(NCLVL1, "nfs41_name_cache_remove: need to find attributes for %s\n", path);
1116  attributes = attr_cache_search(&cache->attributes, fileid);
1117  if (attributes)
1118  attributes->numlinks--;
1119  goto out_unlock;
1120 }
1121 
1123  IN struct nfs41_name_cache *cache,
1124  IN const char *src_path,
1125  IN const nfs41_component *src_name,
1126  IN const change_info4 *src_cinfo,
1127  IN const char *dst_path,
1128  IN const nfs41_component *dst_name,
1129  IN const change_info4 *dst_cinfo)
1130 {
1131  struct name_cache_entry *src_parent, *src;
1132  struct name_cache_entry *dst_parent;
1133  int status = NO_ERROR;
1134 
1135  dprintf(NCLVL1, "--> nfs41_name_cache_rename('%s' to '%s')\n",
1136  src_path, dst_path);
1137 
1138  AcquireSRWLockExclusive(&cache->lock);
1139 
1140  if (!name_cache_enabled(cache)) {
1141  status = ERROR_NOT_SUPPORTED;
1142  goto out_unlock;
1143  }
1144 
1145  /* look up dst_parent */
1146  status = name_cache_lookup(cache, 0, dst_path,
1147  dst_name->name, NULL, NULL, &dst_parent, NULL);
1148  /* we can't create the dst entry without a parent */
1149  if (status || dst_parent->attributes == NULL) {
1150  /* if src exists, make it negative */
1151  dprintf(NCLVL1, "nfs41_name_cache_rename: adding negative cache "
1152  "entry for %.*s\n", src_name->len, src_name->name);
1153  status = name_cache_lookup(cache, 0, src_path,
1154  src_name->name + src_name->len, NULL, NULL, &src, NULL);
1155  if (status == NO_ERROR) {
1158  }
1159  status = ERROR_PATH_NOT_FOUND;
1160  goto out_unlock;
1161  }
1162 
1163  /* look up src_parent and src */
1164  status = name_cache_lookup(cache, 0, src_path,
1165  src_name->name + src_name->len, NULL, &src_parent, &src, NULL);
1166  /* we can't create the dst entry without valid attributes */
1167  if (status || src->attributes == NULL) {
1168  /* remove dst if it exists */
1169  struct name_cache_entry *dst;
1170  dprintf(NCLVL1, "nfs41_name_cache_rename: removing negative cache "
1171  "entry for %.*s\n", dst_name->len, dst_name->name);
1172  dst = name_cache_search(cache, dst_parent, dst_name);
1173  if (dst) name_cache_unlink(cache, dst);
1174  goto out_unlock;
1175  }
1176 
1177  if (name_cache_entry_changed(cache, dst_parent, dst_cinfo)) {
1178  name_cache_entry_invalidate(cache, dst_parent);
1179  /* if dst_parent and src_parent are both gone,
1180  * we no longer have an entry to rename */
1181  if (dst_parent == src_parent)
1182  goto out_unlock;
1183  } else {
1184  struct name_cache_entry *existing;
1185  existing = name_cache_search(cache, dst_parent, dst_name);
1186  if (existing) {
1187  if (existing == src)
1188  goto out_unlock;
1189  /* remove the existing entry, but don't unlink it yet;
1190  * we may reuse it for a negative entry */
1191  name_cache_remove(existing, dst_parent);
1192  }
1193 
1194  /* move the src entry under dst_parent */
1195  name_cache_remove(src, src_parent);
1196  name_cache_entry_rename(src, dst_name);
1197  name_cache_insert(src, dst_parent);
1198 
1199  if (existing) {
1200  /* recycle 'existing' as the negative entry 'src' */
1201  name_cache_entry_rename(existing, src_name);
1202  name_cache_insert(existing, src_parent);
1203  }
1204  src = existing;
1205  }
1206 
1207  if (name_cache_entry_changed(cache, src_parent, src_cinfo)) {
1208  name_cache_entry_invalidate(cache, src_parent);
1209  goto out_unlock;
1210  }
1211 
1212  /* leave a negative entry where the file used to be */
1213  if (src == NULL) {
1214  /* src was moved, create a new entry in its place */
1215  status = name_cache_find_or_create(cache, src_parent, src_name, &src);
1216  if (status)
1217  goto out_unlock;
1218  }
1221 
1222 out_unlock:
1223  ReleaseSRWLockExclusive(&cache->lock);
1224 
1225  dprintf(NCLVL1, "<-- nfs41_name_cache_rename() returning %d\n", status);
1226  return status;
1227 }
1228 
1229 /* nfs41_name_cache_resolve_fh() */
1230 
1231 #define MAX_PUTFH_PER_COMPOUND 16
1232 
1234  IN struct nfs41_name_cache *cache,
1236  IN OUT const char **path_pos,
1237  IN uint32_t max_components,
1238  OUT nfs41_path_fh *files,
1239  OUT uint32_t *count)
1240 {
1241  struct name_cache_entry *target;
1242  const char *path_end = path->path + path->len;
1244  uint32_t i;
1245  int status;
1246 
1247  *count = 0;
1248 
1249  AcquireSRWLockShared(&cache->lock);
1250 
1251  /* look up the parent of the first component */
1252  status = name_cache_lookup(cache, 1, path->path,
1253  *path_pos, NULL, NULL, &target, NULL);
1254  if (status)
1255  goto out_unlock;
1256 
1257  for (i = 0; i < max_components; i++) {
1258  files[i].path = path;
1259  name = &files[i].name;
1260 
1261  if (!next_component(*path_pos, path_end, name))
1262  break;
1263  *path_pos = name->name + name->len;
1264 
1265  target = name_cache_search(cache, target, name);
1266  if (target == NULL || entry_invis(target, NULL)) {
1267  if (is_last_component(name->name, path_end))
1268  status = ERROR_FILE_NOT_FOUND;
1269  else
1270  status = ERROR_PATH_NOT_FOUND;
1271  goto out_unlock;
1272  }
1273  /* make copies for use outside of cache->lock */
1274  fh_copy(&files[i].fh, &target->fh);
1275  (*count)++;
1276  }
1277 
1278 out_unlock:
1279  ReleaseSRWLockShared(&cache->lock);
1280  return *count && status == 0;
1281 }
1282 
1283 static int rpc_array_putfh(
1284  IN nfs41_session *session,
1285  IN nfs41_path_fh *files,
1286  IN uint32_t count,
1287  OUT uint32_t *valid_out)
1288 {
1289  nfs41_compound compound;
1292  nfs41_sequence_args sequence_args;
1293  nfs41_sequence_res sequence_res = { 0 };
1295  nfs41_putfh_res putfh_res[MAX_PUTFH_PER_COMPOUND] = { 0 };
1296  uint32_t i;
1297  int status;
1298 
1299  *valid_out = 0;
1300 
1301  compound_init(&compound, argops, resops, "array_putfh");
1302 
1303  compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res);
1304  nfs41_session_sequence(&sequence_args, session, 0);
1305 
1306  for (i = 0; i < count; i++){
1307  compound_add_op(&compound, OP_PUTFH, &putfh_args[i], &putfh_res[i]);
1308  putfh_args[i].file = &files[i];
1309  putfh_args[i].in_recovery = 1;
1310  }
1311 
1312  status = compound_encode_send_decode(session, &compound, TRUE);
1313  if (status) goto out;
1314 
1315  status = sequence_res.sr_status;
1316  if (status) goto out;
1317 
1318  for (i = 0; i < count; i++) {
1319  status = putfh_res[i].status;
1320  if (status) break;
1321  }
1322  *valid_out = i;
1323 out:
1324  return status;
1325 }
1326 
1328  IN struct nfs41_name_cache *cache,
1329  IN nfs41_session *session,
1330  IN const nfs41_abs_path *path,
1331  IN const nfs41_component *component)
1332 {
1333  struct name_cache_entry *target;
1334  int status;
1335 
1336  dprintf(NCLVL1, "--> delete_stale_component('%s')\n",
1337  component->name);
1338 
1339  AcquireSRWLockExclusive(&cache->lock);
1340 
1341  status = name_cache_lookup(cache, 0, path->path,
1342  component->name + component->len, NULL, NULL, &target, NULL);
1343  if (status == NO_ERROR)
1344  name_cache_unlink(cache, target);
1345 
1346  ReleaseSRWLockExclusive(&cache->lock);
1347 
1348  dprintf(NCLVL1, "<-- delete_stale_component() returning %d\n", status);
1349  return status;
1350 }
1351 
1353  IN const nfs41_session *session)
1354 {
1355  const uint32_t comps = session->fore_chan_attrs.ca_maxoperations - 1;
1356  return min(comps, MAX_PUTFH_PER_COMPOUND);
1357 }
1358 
1360  IN struct nfs41_name_cache *cache,
1361  IN nfs41_session *session,
1363 {
1365  const char *path_pos = path->path;
1366  const char* const path_end = path->path + path->len;
1367  const uint32_t max_components = max_putfh_components(session);
1368  uint32_t count, index;
1369  int status = NO_ERROR;
1370 
1371  AcquireSRWLockShared(&cache->lock);
1372 
1373  /* if there's no cache, don't check any components */
1374  if (!name_cache_enabled(cache))
1375  path_pos = path_end;
1376 
1377  ReleaseSRWLockShared(&cache->lock);
1378 
1379  /* hold a lock on the path to protect against rename */
1380  AcquireSRWLockShared(&path->lock);
1381 
1382  while (get_path_fhs(cache, path, &path_pos, max_components, files, &count)) {
1383  status = rpc_array_putfh(session, files, count, &index);
1384 
1385  if (status == NFS4ERR_STALE || status == NFS4ERR_FHEXPIRED) {
1386  status = delete_stale_component(cache,
1387  session, path, &files[index].name);
1388  break;
1389  }
1390  if (status) {
1391  status = nfs_to_windows_error(status, ERROR_FILE_NOT_FOUND);
1392  break;
1393  }
1394  }
1395 
1396  ReleaseSRWLockShared(&path->lock);
1397 
1398  return status;
1399 }
static void attr_cache_free(IN struct attr_cache *cache)
Definition: name_cache.c:210
#define MAX_PUTFH_PER_COMPOUND
Definition: name_cache.c:1231
Definition: cache.c:46
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:54
char * name
Definition: wpp.c:36
#define IN
Definition: typedefs.h:38
nfs41_path_fh * file
Definition: nfs41_ops.h:510
#define ERROR_FILE_EXISTS
Definition: winerror.h:165
int nfs_to_windows_error(int status, int default_error)
Definition: util.c:235
#define TRUE
Definition: types.h:120
static int name_cache_insert(IN struct name_cache_entry *entry, IN struct name_cache_entry *parent)
Definition: name_cache.c:696
#define NAME_CACHE_EXPIRATION
Definition: name_cache.c:42
static void copy_attrs(OUT nfs41_file_info *dst, IN const struct attr_cache_entry *src)
Definition: name_cache.c:329
RB_HEAD(attr_tree, attr_cache_entry)
static void name_cache_entry_updated(IN struct nfs41_name_cache *cache, IN struct name_cache_entry *entry)
Definition: name_cache.c:510
#define NFS41_MAX_COMPONENT_LEN
Definition: nfs41_const.h:45
struct outqueuenode * head
Definition: adnsresfilter.c:66
int nfs41_name_cache_free(IN struct nfs41_name_cache **cache_out)
Definition: name_cache.c:796
int32_t bool_t
Definition: types.h:101
#define RB_INSERT(name, x, y)
Definition: tree.h:726
GLsizei const GLchar ** path
Definition: glext.h:7234
GLuint GLuint GLsizei count
Definition: gl.h:1545
static __inline void attr_cache_entry_ref(IN struct attr_cache *cache, IN struct attr_cache_entry *entry)
Definition: name_cache.c:157
int compound_encode_send_decode(nfs41_session *session, nfs41_compound *compound, bool_t try_recovery)
#define free
Definition: debug_ros.c:5
uint8_t entry
Definition: isohybrid.c:63
static __inline bool_t name_cache_enabled(IN struct nfs41_name_cache *cache)
Definition: name_cache.c:401
uint32_t max_delegations
Definition: name_cache.c:391
__WINE_SERVER_LIST_INLINE void list_add_head(struct list *list, struct list *elem)
Definition: list.h:96
open_delegation_type4
Definition: nfs41_ops.h:585
static int attr_cache_insert(IN struct attr_cache *cache, IN struct attr_cache_entry *entry)
Definition: name_cache.c:229
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define assert(x)
Definition: debug.h:53
#define RB_FIND(name, x, y)
Definition: tree.h:728
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
static int attr_cache_find_or_create(IN struct attr_cache *cache, IN uint64_t fileid, OUT struct attr_cache_entry **entry_out)
Definition: name_cache.c:244
int nfs41_name_cache_lookup(IN struct nfs41_name_cache *cache, IN const char *path, IN const char *path_end, OUT OPTIONAL const char **remaining_path_out, OUT OPTIONAL nfs41_fh *parent_out, OUT OPTIONAL nfs41_fh *target_out, OUT OPTIONAL nfs41_file_info *info_out, OUT OPTIONAL bool_t *is_negative)
Definition: name_cache.c:824
static int attr_cache_entry_create(IN struct attr_cache *cache, IN uint64_t fileid, OUT struct attr_cache_entry **entry_out)
Definition: name_cache.c:123
static __inline int attr_cache_entry_expired(IN const struct attr_cache_entry *entry)
Definition: name_cache.c:178
uint32_t expiration
Definition: name_cache.c:387
struct attr_cache attributes
Definition: name_cache.c:385
uint32_t max_entries
Definition: name_cache.c:389
__u16 time
Definition: mkdosfs.c:366
#define RB_FOREACH_SAFE(x, name, head, y)
Definition: tree.h:745
#define NO_ERROR
Definition: dderror.h:5
__u32 hidden
Definition: mkdosfs.c:371
#define ATTR_ENTRY_SIZE
Definition: name_cache.c:103
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
GLuint const GLubyte GLvoid * src
Definition: s_context.h:57
GLenum GLclampf GLint i
Definition: glfuncs.h:14
struct list_entry exp_entries
Definition: name_cache.c:386
STRSAFEAPI StringCchCopyNA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc, size_t cchToCopy)
Definition: strsafe.h:230
Definition: name_cache.c:80
static __inline uint32_t max_putfh_components(IN const nfs41_session *session)
Definition: name_cache.c:1352
#define dprintf
Definition: regdump.c:33
int nfs41_name_cache_insert(IN struct nfs41_name_cache *cache, IN const char *path, IN const nfs41_component *name, IN OPTIONAL const nfs41_fh *fh, IN OPTIONAL const nfs41_file_info *info, IN OPTIONAL const change_info4 *cinfo, IN enum open_delegation_type4 delegation)
Definition: name_cache.c:923
static __inline bool_t is_delegation(IN enum open_delegation_type4 type)
Definition: name_cache.c:72
smooth NULL
Definition: ftsmooth.c:416
unsigned char
Definition: typeof.h:27
uint32_t delegations
Definition: name_cache.c:390
struct attr_cache_entry * pool
Definition: name_cache.c:109
bool_t next_component(IN const char *path, IN const char *path_end, OUT nfs41_component *component)
Definition: util.c:305
#define name_entry(pos)
Definition: name_cache.c:399
int __cdecl system(_In_opt_z_ const char *_Command)
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
static int name_cache_lookup(IN struct nfs41_name_cache *cache, IN bool_t skip_invis, IN const char *path, IN const char *path_end, OUT OPTIONAL const char **remaining_path_out, OUT OPTIONAL struct name_cache_entry **parent_out, OUT OPTIONAL struct name_cache_entry **target_out, OUT OPTIONAL bool_t *is_negative)
Definition: name_cache.c:648
nfs41_abs_path * path
Definition: nfs41_types.h:60
#define NAME_CACHE_MAX_ENTRIES
Definition: name_cache.c:750
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
char component[NFS41_MAX_COMPONENT_LEN]
Definition: name_cache.c:363
GLsizeiptr size
Definition: glext.h:5919
int nfs41_attr_cache_update(IN struct nfs41_name_cache *cache, IN uint64_t fileid, IN const nfs41_file_info *info)
Definition: name_cache.c:891
int nfs41_name_cache_delegreturn(IN struct nfs41_name_cache *cache, IN uint64_t fileid, IN const char *path, IN const nfs41_component *name)
Definition: name_cache.c:1012
static int name_cache_entry_create(IN struct nfs41_name_cache *cache, IN const nfs41_component *component, OUT struct name_cache_entry **entry_out)
Definition: name_cache.c:459
const char * name
Definition: nfs41_types.h:48
r parent
Definition: btrfs.c:2644
static void name_cache_entry_invalidate(IN struct nfs41_name_cache *cache, IN struct name_cache_entry *entry)
Definition: name_cache.c:587
#define attr_entry(pos)
Definition: name_cache.c:121
uint32_t status
Definition: nfs41_ops.h:515
static int name_cache_find_or_create(IN struct nfs41_name_cache *cache, IN struct name_cache_entry *parent, IN const nfs41_component *component, OUT struct name_cache_entry **target_out)
Definition: name_cache.c:712
struct name_cache_entry * pool
Definition: name_cache.c:384
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
static FILE * out
Definition: regtests2xml.c:44
static void name_cache_unlink_children_recursive(IN struct nfs41_name_cache *cache, IN struct name_cache_entry *parent)
Definition: name_cache.c:450
static void free_entries(Entry *dir)
Definition: winefile.c:319
static bool_t get_path_fhs(IN struct nfs41_name_cache *cache, IN nfs41_abs_path *path, IN OUT const char **path_pos, IN uint32_t max_components, OUT nfs41_path_fh *files, OUT uint32_t *count)
Definition: name_cache.c:1233
static int name_cache_entry_changed(IN struct nfs41_name_cache *cache, IN struct name_cache_entry *entry, IN const change_info4 *cinfo)
Definition: name_cache.c:563
#define RB_GENERATE(name, type, field, cmp)
Definition: tree.h:400
static __inline void attr_cache_entry_deref(IN struct attr_cache *cache, IN struct attr_cache_entry *entry)
Definition: name_cache.c:166
void fh_copy(OUT nfs41_fh *dst, IN const nfs41_fh *src)
Definition: util.c:354
static __inline void copy_fh(OUT nfs41_fh *dst, IN OPTIONAL const struct name_cache_entry *src)
Definition: name_cache.c:814
#define index(s, c)
Definition: various.h:29
void compound_add_op(nfs41_compound *compound, uint32_t opnum, void *arg, void *res)
static __inline void name_cache_entry_rename(OUT struct name_cache_entry *entry, IN const nfs41_component *component)
Definition: name_cache.c:407
static IOleCache * cache
Definition: ole2.c:81
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:82
static int name_cache_entry_update(IN struct nfs41_name_cache *cache, IN struct name_cache_entry *entry, IN OPTIONAL const nfs41_fh *fh, IN OPTIONAL const nfs41_file_info *info, IN enum open_delegation_type4 delegation)
Definition: name_cache.c:519
VOID WINAPI InitializeSRWLock(PSRWLOCK Lock)
Definition: sync.c:75
GLenum mode
Definition: glext.h:6217
__WINE_SERVER_LIST_INLINE int list_empty(const struct list *list)
Definition: list.h:143
#define ERROR_TOO_MANY_OPEN_FILES
Definition: winerror.h:107
UINT64 uint64_t
Definition: types.h:77
int nfs41_name_cache_rename(IN struct nfs41_name_cache *cache, IN const char *src_path, IN const nfs41_component *src_name, IN const change_info4 *src_cinfo, IN const char *dst_path, IN const nfs41_component *dst_name, IN const change_info4 *dst_cinfo)
Definition: name_cache.c:1122
__kernel_time_t time_t
Definition: linux.h:252
int name_cmp(struct name_cache_entry *lhs, struct name_cache_entry *rhs)
Definition: name_cache.c:375
nfs41_fh fh
Definition: name_cache.c:364
struct name_cache_entry * root
Definition: name_cache.c:383
Definition: services.c:325
#define min(a, b)
Definition: monoChain.cc:55
Definition: list.h:27
GLuint const GLubyte GLvoid const GLvoid * dst
Definition: s_context.h:57
UINT32 uint32_t
Definition: types.h:75
static __inline void name_cache_remove(IN struct name_cache_entry *entry, IN struct name_cache_entry *parent)
Definition: name_cache.c:416
static int delete_stale_component(IN struct nfs41_name_cache *cache, IN nfs41_session *session, IN const nfs41_abs_path *path, IN const nfs41_component *component)
Definition: name_cache.c:1327
static struct name_cache_entry * name_cache_search(IN struct nfs41_name_cache *cache, IN struct name_cache_entry *parent, IN const nfs41_component *component)
Definition: name_cache.c:601
#define RB_REMOVE(name, x, y)
Definition: tree.h:727
void nfs41_session_sequence(struct __nfs41_sequence_args *args, nfs41_session *session, bool_t cachethis)
static void attr_cache_update(IN struct attr_cache_entry *entry, IN const nfs41_file_info *info, IN enum open_delegation_type4 delegation)
Definition: name_cache.c:282
bool_t is_last_component(IN const char *path, IN const char *path_end)
Definition: util.c:330
static int rpc_array_putfh(IN nfs41_session *session, IN nfs41_path_fh *files, IN uint32_t count, OUT uint32_t *valid_out)
Definition: name_cache.c:1283
#define ERROR_NOT_SUPPORTED
Definition: compat.h:90
Definition: name.c:36
#define calloc
Definition: rosglue.h:14
void compound_init(nfs41_compound *compound, nfs_argop4 *argops, nfs_resop4 *resops, const char *tag)
#define OUT
Definition: typedefs.h:39
static int attr_cache_init(IN struct attr_cache *cache, IN uint32_t max_entries)
Definition: name_cache.c:186
#define NAME_ENTRY_SIZE
Definition: name_cache.c:373
int nfs41_name_cache_remove(IN struct nfs41_name_cache *cache, IN const char *path, IN const nfs41_component *name, IN uint64_t fileid, IN const change_info4 *cinfo)
Definition: name_cache.c:1066
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
static void name_cache_entry_accessed(IN struct nfs41_name_cache *cache, IN struct name_cache_entry *entry)
Definition: name_cache.c:492
GLenum target
Definition: glext.h:7315
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:106
uint32_t entries
Definition: name_cache.c:388
char path[NFS41_MAX_PATH_LEN]
Definition: nfs41_types.h:42
static __inline void attr_cache_entry_free(IN struct attr_cache *cache, IN struct attr_cache_entry *entry)
Definition: name_cache.c:147
static int entry_invis(IN struct name_cache_entry *entry, OUT OPTIONAL bool_t *is_negative)
Definition: name_cache.c:624
INT64 int64_t
Definition: types.h:72
int nfs41_name_cache_remove_stale(IN struct nfs41_name_cache *cache, IN nfs41_session *session, IN nfs41_abs_path *path)
Definition: name_cache.c:1359
int attr_cmp(struct attr_cache_entry *lhs, struct attr_cache_entry *rhs)
Definition: name_cache.c:113
unsigned short len
Definition: nfs41_types.h:49
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 SERVICE_STATUS status
Definition: service.c:31
Definition: name_cache.c:362
#define RB_ENTRY(type)
Definition: tree.h:310
VOID WINAPI AcquireSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:61
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:89
static __inline void name_cache_unlink(IN struct nfs41_name_cache *cache, IN struct name_cache_entry *entry)
Definition: name_cache.c:428
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
static struct attr_cache_entry * attr_cache_search(IN struct attr_cache *cache, IN uint64_t fileid)
Definition: name_cache.c:219
Definition: ps.c:97
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
int nfs41_name_cache_create(OUT struct nfs41_name_cache **cache_out)
Definition: name_cache.c:752
GLuint const GLchar * name
Definition: glext.h:6031