ReactOS  0.4.13-dev-540-g8f04a09
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 {
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)) {
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)
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))
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 */
259  if (status)
260  goto out;
261 
263  if (status)
264  goto out_err_free;
265  }
266 
267  /* take a reference on success */
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:
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);
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 {
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)
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)) {
471  goto out;
472  }
473  entry = name_entry(cache->exp_entries.prev);
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 
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;
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  }
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;
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  }
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;
672  goto out;
673  }
674 
675  while (next_component(path_pos, path_end, &component)) {
676  parent = target;
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))
683  else
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))
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 
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);
768  cache->expiration = NAME_CACHE_EXPIRATION;
769  cache->max_entries = NAME_CACHE_MAX_ENTRIES;
770  cache->max_delegations = NAME_CACHE_MAX_ENTRIES / 2;
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 
839 
840  if (!name_cache_enabled(cache)) {
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:
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 
870 
871  if (!name_cache_enabled(cache)) {
873  goto out_unlock;
874  }
875 
876  entry = attr_cache_search(&cache->attributes, fileid);
879  goto out_unlock;
880  }
881 
882  copy_attrs(info_out, entry);
883 
884 out_unlock:
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 
902 
903  if (!name_cache_enabled(cache)) {
905  goto out_unlock;
906  }
907 
908  entry = attr_cache_search(&cache->attributes, fileid);
909  if (entry == NULL) {
911  goto out_unlock;
912  }
913 
915 
916 out_unlock:
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 
939 
940  if (!name_cache_enabled(cache)) {
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) {
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 };
958  if (status)
959  goto out_err_deleg;
960  }
961  target = cache->root;
962  } else {
963  /* find/create an entry under its parent */
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)) {
971  goto out_err_deleg;
972  }
973 
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:
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 */
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
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 
1026 
1027  if (!name_cache_enabled(cache)) {
1029  goto out_unlock;
1030  }
1031 
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);
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) {
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:
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 
1080 
1081  if (!name_cache_enabled(cache)) {
1083  goto out_unlock;
1084  }
1085 
1087  name->name + name->len, NULL, &parent, &target, NULL);
1089  goto out_attributes;
1090 
1091  if (cinfo && name_cache_entry_changed(cache, parent, cinfo)) {
1093  goto out_attributes;
1094  }
1095 
1097  goto out_attributes;
1098 
1099  if (target->attributes)
1100  target->attributes->numlinks--;
1101 
1102  /* make this a negative entry and unlink children */
1105 
1106 out_unlock:
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 
1139 
1140  if (!name_cache_enabled(cache)) {
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  }
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:
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 
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 
1266  if (target == NULL || entry_invis(target, NULL)) {
1267  if (is_last_component(name->name, path_end))
1269  else
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:
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 
1340 
1341  status = name_cache_lookup(cache, 0, path->path,
1342  component->name + component->len, NULL, NULL, &target, NULL);
1343  if (status == NO_ERROR)
1345 
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 
1372 
1373  /* if there's no cache, don't check any components */
1374  if (!name_cache_enabled(cache))
1375  path_pos = path_end;
1376 
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 
1387  session, path, &files[index].name);
1388  break;
1389  }
1390  if (status) {
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
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
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
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
unsigned int count
Definition: notification.c:64
__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
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
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
HANDLE lock
Definition: cache.c:50
unsigned char
Definition: typeof.h:29
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
GLuint index
Definition: glext.h:6031
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
#define NAME_CACHE_MAX_ENTRIES
Definition: name_cache.c:750
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
struct attr_tree head
Definition: name_cache.c: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
r parent
Definition: btrfs.c:2708
static void free_entry(Entry *entry)
Definition: winefile.c:304
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 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:75
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:82
uint32_t entry
Definition: isohybrid.c:63
struct list_entry free_entries
Definition: name_cache.c:110
GLenum src
Definition: glext.h:6340
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
unsigned char fh[NFS4_FHSIZE]
Definition: nfs41_types.h:53
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
GLenum GLenum dst
Definition: glext.h:6340
#define min(a, b)
Definition: monoChain.cc:55
Definition: list.h:27
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
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
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
WCHAR * name
Definition: name.c:40
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