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:
Casey Bodley 2011-07-06 11:05:45 -04:00 committed by unknown
parent ee71a62af2
commit 38259e0017
4 changed files with 124 additions and 32 deletions

View file

@ -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)

View file

@ -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:

View file

@ -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,

View file

@ -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;
}