deleg: delegation support for name/attr cache
when a delegation is granted by OPEN, its delegation type is passed to nfs41_name_cache_insert(). as long as the delegation is held, its name_cache_entry is kept out of the cache.exp_entries list to prevent it from expiring. an extra reference is held on the attr_cache_entry as well, so it sticks around even if the name_cache_entry is removed (a parent expires, for example). new function nfs41_name_cache_delegreturn() adds the name_cache_entry back to the list, and releases the extra attr_cache_entry reference Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
parent
ee71a62af2
commit
38259e0017
4 changed files with 124 additions and 32 deletions
|
|
@ -223,8 +223,8 @@ static int server_lookup(
|
|||
/* add the file handle and attributes to the name cache */
|
||||
memcpy(&res->getrootattr.info->attrmask,
|
||||
&res->getrootattr.obj_attributes.attrmask, sizeof(bitmap4));
|
||||
nfs41_name_cache_insert(session_name_cache(session),
|
||||
path, &name, &dir->fh, res->getrootattr.info, NULL);
|
||||
nfs41_name_cache_insert(session_name_cache(session), path, &name,
|
||||
&dir->fh, res->getrootattr.info, NULL, OPEN_DELEGATE_NONE);
|
||||
}
|
||||
file = dir;
|
||||
|
||||
|
|
@ -245,8 +245,8 @@ static int server_lookup(
|
|||
if (parent_out) *parent_out = file;
|
||||
} else if (res->lookup[i].status == NFS4ERR_NOENT) {
|
||||
/* insert a negative lookup entry */
|
||||
nfs41_name_cache_insert(session_name_cache(session),
|
||||
path, args->lookup[i].name, NULL, NULL, NULL);
|
||||
nfs41_name_cache_insert(session_name_cache(session), path,
|
||||
args->lookup[i].name, NULL, NULL, NULL, OPEN_DELEGATE_NONE);
|
||||
}
|
||||
status = res->lookup[i].status; if (status) break;
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ static int server_lookup(
|
|||
&res->getattr[i].obj_attributes.attrmask, sizeof(bitmap4));
|
||||
nfs41_name_cache_insert(session_name_cache(session),
|
||||
path, args->lookup[i].name, &res->file[i].fh,
|
||||
res->getattr[i].info, NULL);
|
||||
res->getattr[i].info, NULL, OPEN_DELEGATE_NONE);
|
||||
|
||||
if (i == count-1) {
|
||||
if (target_out)
|
||||
|
|
|
|||
|
|
@ -69,9 +69,10 @@ struct attr_cache_entry {
|
|||
uint32_t time_modify_ns;
|
||||
uint32_t numlinks;
|
||||
uint32_t mode;
|
||||
unsigned short ref_count;
|
||||
unsigned char type;
|
||||
unsigned char invalidated;
|
||||
unsigned ref_count : 26;
|
||||
unsigned type : 4;
|
||||
unsigned invalidated : 1;
|
||||
unsigned delegated : 1;
|
||||
};
|
||||
#define ATTR_ENTRY_SIZE sizeof(struct attr_cache_entry)
|
||||
|
||||
|
|
@ -245,7 +246,8 @@ out_err_free:
|
|||
|
||||
static void attr_cache_update(
|
||||
IN struct attr_cache_entry *entry,
|
||||
IN const nfs41_file_info *info)
|
||||
IN const nfs41_file_info *info,
|
||||
IN enum open_delegation_type4 delegation)
|
||||
{
|
||||
/* update the attributes present in mask */
|
||||
if (info->attrmask.count >= 1) {
|
||||
|
|
@ -277,6 +279,9 @@ static void attr_cache_update(
|
|||
entry->time_modify_ns = info->time_modify.nseconds;
|
||||
}
|
||||
}
|
||||
|
||||
if (delegation == OPEN_DELEGATE_READ || delegation == OPEN_DELEGATE_WRITE)
|
||||
entry->delegated = TRUE;
|
||||
}
|
||||
|
||||
static void copy_attrs(
|
||||
|
|
@ -430,15 +435,18 @@ static void name_cache_entry_refresh(
|
|||
/* update the expiration timer */
|
||||
entry->expiration = time(NULL) + cache->expiration;
|
||||
/* move the entry to the front of cache->exp_entries */
|
||||
list_remove(&entry->exp_entry);
|
||||
list_add_head(&cache->exp_entries, &entry->exp_entry);
|
||||
if (!list_empty(&entry->exp_entry)) {
|
||||
list_remove(&entry->exp_entry);
|
||||
list_add_head(&cache->exp_entries, &entry->exp_entry);
|
||||
}
|
||||
}
|
||||
|
||||
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 OPTIONAL const nfs41_file_info *info,
|
||||
IN enum open_delegation_type4 delegation)
|
||||
{
|
||||
int status = NO_ERROR;
|
||||
|
||||
|
|
@ -453,8 +461,17 @@ static int name_cache_entry_update(
|
|||
status = attr_cache_find_or_create(&cache->attributes,
|
||||
info->fileid, &entry->attributes);
|
||||
|
||||
if (status == NO_ERROR)
|
||||
attr_cache_update(entry->attributes, info);
|
||||
if (status == NO_ERROR) {
|
||||
attr_cache_update(entry->attributes, info, delegation);
|
||||
|
||||
/* hold a reference as long as we have the delegation */
|
||||
if (delegation == OPEN_DELEGATE_READ || delegation == OPEN_DELEGATE_WRITE)
|
||||
attr_cache_entry_ref(&cache->attributes, entry->attributes);
|
||||
|
||||
/* keep the entry from expiring */
|
||||
if (entry->attributes->delegated)
|
||||
list_remove(&entry->exp_entry);
|
||||
}
|
||||
} else if (entry->attributes) {
|
||||
/* positive -> negative entry, deref the attributes */
|
||||
attr_cache_entry_deref(&cache->attributes, entry->attributes);
|
||||
|
|
@ -495,7 +512,7 @@ static void name_cache_entry_invalidate(
|
|||
dprintf(NCLVL1, "name_cache_entry_invalidate('%s')\n", entry->component);
|
||||
|
||||
if (entry->attributes) {
|
||||
/* flag attributes so that entry_has_expired() will return true
|
||||
/* flag attributes so that entry_invis() will return true
|
||||
* if another entry attempts to use them */
|
||||
entry->attributes->invalidated = 1;
|
||||
}
|
||||
|
|
@ -530,7 +547,7 @@ static int entry_invis(
|
|||
OUT OPTIONAL bool_t *is_negative)
|
||||
{
|
||||
/* name entry timer expired? */
|
||||
if (time(NULL) > entry->expiration) {
|
||||
if (!list_empty(&entry->exp_entry) && time(NULL) > entry->expiration) {
|
||||
dprintf(NCLVL2, "name_entry_expired('%s')\n", entry->component);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -814,7 +831,7 @@ int nfs41_attr_cache_update(
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
attr_cache_update(entry, info);
|
||||
attr_cache_update(entry, info, OPEN_DELEGATE_NONE);
|
||||
|
||||
out_unlock:
|
||||
ReleaseSRWLockExclusive(&cache->lock);
|
||||
|
|
@ -829,7 +846,8 @@ int nfs41_name_cache_insert(
|
|||
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 OPTIONAL const change_info4 *cinfo,
|
||||
IN enum open_delegation_type4 delegation)
|
||||
{
|
||||
struct name_cache_entry *grandparent, *parent, *target;
|
||||
int status;
|
||||
|
|
@ -851,28 +869,29 @@ int nfs41_name_cache_insert(
|
|||
const nfs41_component name = { "ROOT", 4 };
|
||||
status = name_cache_entry_create(cache, &name, &cache->root);
|
||||
if (status)
|
||||
goto out_unlock;
|
||||
goto out_err_deleg;
|
||||
}
|
||||
|
||||
status = name_cache_entry_update(cache, cache->root, fh, info);
|
||||
goto out_unlock;
|
||||
status = name_cache_entry_update(cache,
|
||||
cache->root, fh, info, delegation);
|
||||
goto out_err_deleg;
|
||||
}
|
||||
|
||||
status = name_cache_lookup(cache, 0, path, name->name,
|
||||
NULL, &grandparent, &parent, NULL);
|
||||
if (status)
|
||||
goto out_unlock;
|
||||
goto out_err_deleg;
|
||||
|
||||
if (cinfo && name_cache_entry_changed(cache, parent, cinfo)) {
|
||||
name_cache_entry_invalidate(cache, parent);
|
||||
goto out_unlock;
|
||||
goto out_err_deleg;
|
||||
}
|
||||
|
||||
status = name_cache_find_or_create(cache, parent, name, &target);
|
||||
if (status)
|
||||
goto out_unlock;
|
||||
goto out_err_deleg;
|
||||
|
||||
status = name_cache_entry_update(cache, target, fh, info);
|
||||
status = name_cache_entry_update(cache, target, fh, info, delegation);
|
||||
|
||||
out_unlock:
|
||||
ReleaseSRWLockExclusive(&cache->lock);
|
||||
|
|
@ -880,6 +899,66 @@ out_unlock:
|
|||
dprintf(NCLVL1, "<-- nfs41_name_cache_insert() returning %d\n",
|
||||
status);
|
||||
return status;
|
||||
|
||||
out_err_deleg:
|
||||
if (delegation == OPEN_DELEGATE_READ || delegation == OPEN_DELEGATE_WRITE) {
|
||||
/* we still need a reference to the attributes for the delegation */
|
||||
struct attr_cache_entry *attributes;
|
||||
if (attr_cache_find_or_create(&cache->attributes,
|
||||
info->fileid, &attributes) == NO_ERROR)
|
||||
attr_cache_update(attributes, info, delegation);
|
||||
}
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
int nfs41_name_cache_delegreturn(
|
||||
IN struct nfs41_name_cache *cache,
|
||||
IN uint64_t fileid,
|
||||
IN const char *path,
|
||||
IN const nfs41_component *name)
|
||||
{
|
||||
struct name_cache_entry *parent, *target;
|
||||
struct attr_cache_entry *attributes;
|
||||
int status;
|
||||
|
||||
dprintf(NCLVL1, "--> nfs41_name_cache_delegreturn(%llu, '%s')\n",
|
||||
fileid, path);
|
||||
|
||||
AcquireSRWLockExclusive(&cache->lock);
|
||||
|
||||
if (!name_cache_enabled(cache)) {
|
||||
status = ERROR_NOT_SUPPORTED;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
status = name_cache_lookup(cache, 0, path,
|
||||
name->name + name->len, NULL, &parent, &target, NULL);
|
||||
if (status == NO_ERROR) {
|
||||
/* put the name cache entry back on the exp_entries list */
|
||||
list_add_head(&cache->exp_entries, &target->exp_entry);
|
||||
name_cache_entry_refresh(cache, target);
|
||||
|
||||
attributes = target->attributes;
|
||||
} else {
|
||||
/* should still have an attr cache entry */
|
||||
attributes = attr_cache_search(&cache->attributes, fileid);
|
||||
}
|
||||
|
||||
if (attributes == NULL) {
|
||||
status = ERROR_FILE_NOT_FOUND;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* release the reference from name_cache_entry_update() */
|
||||
attributes->delegated = FALSE;
|
||||
attr_cache_entry_deref(&cache->attributes, attributes);
|
||||
status = NO_ERROR;
|
||||
|
||||
out_unlock:
|
||||
ReleaseSRWLockExclusive(&cache->lock);
|
||||
|
||||
dprintf(NCLVL1, "<-- nfs41_name_cache_delegreturn() returning %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
int nfs41_name_cache_remove(
|
||||
|
|
@ -917,7 +996,7 @@ int nfs41_name_cache_remove(
|
|||
target->attributes->numlinks--;
|
||||
|
||||
/* make this a negative entry and unlink children */
|
||||
name_cache_entry_update(cache, target, NULL, NULL);
|
||||
name_cache_entry_update(cache, target, NULL, NULL, OPEN_DELEGATE_NONE);
|
||||
name_cache_unlink_children_recursive(cache, target);
|
||||
|
||||
out_unlock:
|
||||
|
|
@ -1005,7 +1084,7 @@ int nfs41_name_cache_rename(
|
|||
if (status)
|
||||
goto out_unlock;
|
||||
}
|
||||
name_cache_entry_update(cache, src, NULL, NULL);
|
||||
name_cache_entry_update(cache, src, NULL, NULL, OPEN_DELEGATE_NONE);
|
||||
name_cache_unlink_children_recursive(cache, src);
|
||||
|
||||
out_unlock:
|
||||
|
|
|
|||
|
|
@ -75,7 +75,14 @@ int nfs41_name_cache_insert(
|
|||
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 OPTIONAL const change_info4 *cinfo,
|
||||
IN enum open_delegation_type4 delegation);
|
||||
|
||||
int nfs41_name_cache_delegreturn(
|
||||
IN struct nfs41_name_cache *cache,
|
||||
IN uint64_t fileid,
|
||||
IN const char *path,
|
||||
IN const nfs41_component *name);
|
||||
|
||||
int nfs41_name_cache_remove(
|
||||
IN struct nfs41_name_cache *cache,
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ int nfs41_rpc_open(
|
|||
AcquireSRWLockShared(&file->path->lock);
|
||||
nfs41_name_cache_insert(session_name_cache(session),
|
||||
file->path->path, &file->name, &file->fh,
|
||||
info, &open_res.resok4.cinfo);
|
||||
info, &open_res.resok4.cinfo, delegation->type);
|
||||
ReleaseSRWLockShared(&file->path->lock);
|
||||
|
||||
if (create == OPEN4_CREATE)
|
||||
|
|
@ -558,7 +558,7 @@ int nfs41_create(
|
|||
AcquireSRWLockShared(&file->path->lock);
|
||||
nfs41_name_cache_insert(session_name_cache(session),
|
||||
file->path->path, &file->name, &file->fh,
|
||||
&file_info, &create_res.cinfo);
|
||||
&file_info, &create_res.cinfo, OPEN_DELEGATE_NONE);
|
||||
ReleaseSRWLockShared(&file->path->lock);
|
||||
|
||||
nfs41_superblock_space_changed(file->fh.superblock);
|
||||
|
|
@ -1401,7 +1401,7 @@ int nfs41_link(
|
|||
AcquireSRWLockShared(&dst_dir->path->lock);
|
||||
nfs41_name_cache_insert(session_name_cache(session),
|
||||
dst_dir->path->path, target, &link_out->fh,
|
||||
&info[1], &link_res.cinfo);
|
||||
&info[1], &link_res.cinfo, OPEN_DELEGATE_NONE);
|
||||
ReleaseSRWLockShared(&dst_dir->path->lock);
|
||||
|
||||
nfs41_superblock_space_changed(dst_dir->fh.superblock);
|
||||
|
|
@ -1562,7 +1562,13 @@ int nfs41_delegreturn(
|
|||
if (status)
|
||||
goto out;
|
||||
|
||||
compound_error(status = compound.res.status);
|
||||
if (compound_error(status = compound.res.status))
|
||||
goto out;
|
||||
|
||||
AcquireSRWLockShared(&file->path->lock);
|
||||
nfs41_name_cache_delegreturn(session_name_cache(session),
|
||||
file->fh.fileid, file->path->path, &file->name);
|
||||
ReleaseSRWLockShared(&file->path->lock);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue