symptom: in certain cases, name_cache_find_or_create() was returning ERROR_FILE_EXISTS, which should never happen!
cause: the string comparisons in name_cache_search() and name_cache_insert() were returning different results when the argument to name_cache_search() is a) not null-terminated, and b) shorter than the other string. this caused name_cache_search() to search the wrong branch of the rbtree and fail to find the component, while name_cache_insert() would correctly find it and return ERROR_FILE_EXISTS
fix: compare the string lengths before calling strncmp() to avoid comparing past the end of the component. moved the comparisons to a separate component_cmp() function called by both name_cache_search() and name_cache_insert() to make sure they get the same result!
Signed-off-by: Casey Bodley <cbodley@umich.edu>
/* negative lookup caching
*
* by caching lookups that result in NOENT, we can avoid sending subsequent
* lookups over the wire. a name cache entry is negative when its attributes
* pointer is NULL. negative entries are created by three functions:
* nfs41_name_cache_remove(), _insert() when called with NULL for the fh and
* attributes, and _rename() for the source entry
*/
Signed-off-by: Casey Bodley <cbodley@umich.edu>
previously, when the name cache encountered a missing/negative/expired entry, it returned the previous two entries as 'target' and 'parent', and nfs41_lookup() started new lookups from the filehandle in 'target'. this differs from nfs41_lookup(), which on NOENT will return NULL for the 'target' and the previous entry as 'parent'. modified name_cache_lookup() to do the same, and updated nfs41_lookup() to start new lookups from the filehandle in 'parent'
now when nfs41_lookup() gets the is_negative flag from nfs41_name_cache_lookup(), it can just return the error without needing to copy the 'target' to 'parent'
Signed-off-by: Casey Bodley <cbodley@umich.edu>
as before, we move the src entry from src_parent to dst_parent. but instead of unlinking the destination entry if it exists, we recycle it as a negative entry where src used to be. if the destination entry doesn't exist, we create a new one for this negative entry
if the dst_parent entry is invalidated by the change_info, we just leave the original src entry in place and make it negative
Signed-off-by: Casey Bodley <cbodley@umich.edu>
negative lookup entries don't have attributes, so we won't invalidate them based on 'change'. name_cache_entry_changed() returns false if entry->attributes == NULL
Signed-off-by: Casey Bodley <cbodley@umich.edu>
instead of calling name_cache_entry_unlink(), nfs41_name_cache_remove() calls name_cache_entry_update() with NULL for fh and info to make it a negative entry, then name_cache_unlink_children_recursive() to remove any children
Signed-off-by: Casey Bodley <cbodley@umich.edu>
marked nfs41_name_cache_insert() parameters fh and info as OPTIONAL; passing NULL designates a negative lookup entry
name_cache_entry_create() no longer calls attr_cache_find_or_create(), and doesn't need the 'fileid' argument
name_cache_entry_update() also makes fh and info OPTIONAL, and handles the cases where we switch from a negative <-> positive entry, calling attr_cache_find_or_create() or attr_cache_entry_deref() as appropriate
removed unused function name_cache_find_or_create(); everything uses name_cache_entry_find_or_create() instead, so renamed that to name_cache_find_or_create()
Signed-off-by: Casey Bodley <cbodley@umich.edu>
added function entry_invis() in addition to entry_has_expired(). entry_invis() returns true if entry_has_expired() or for negative entries. the is_negative flag is set for negative entries (defined as having entry->attributes == NULL), and returned by nfs41_name_cache_lookup(). when nfs41_lookup() sees this flag set, it returns the status without attempting to do any more lookups
Signed-off-by: Casey Bodley <cbodley@umich.edu>