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 */ /* add the file handle and attributes to the name cache */
memcpy(&res->getrootattr.info->attrmask, memcpy(&res->getrootattr.info->attrmask,
&res->getrootattr.obj_attributes.attrmask, sizeof(bitmap4)); &res->getrootattr.obj_attributes.attrmask, sizeof(bitmap4));
nfs41_name_cache_insert(session_name_cache(session), nfs41_name_cache_insert(session_name_cache(session), path, &name,
path, &name, &dir->fh, res->getrootattr.info, NULL); &dir->fh, res->getrootattr.info, NULL, OPEN_DELEGATE_NONE);
} }
file = dir; file = dir;
@ -245,8 +245,8 @@ static int server_lookup(
if (parent_out) *parent_out = file; if (parent_out) *parent_out = file;
} else if (res->lookup[i].status == NFS4ERR_NOENT) { } else if (res->lookup[i].status == NFS4ERR_NOENT) {
/* insert a negative lookup entry */ /* insert a negative lookup entry */
nfs41_name_cache_insert(session_name_cache(session), nfs41_name_cache_insert(session_name_cache(session), path,
path, args->lookup[i].name, NULL, NULL, NULL); args->lookup[i].name, NULL, NULL, NULL, OPEN_DELEGATE_NONE);
} }
status = res->lookup[i].status; if (status) break; status = res->lookup[i].status; if (status) break;
@ -274,7 +274,7 @@ static int server_lookup(
&res->getattr[i].obj_attributes.attrmask, sizeof(bitmap4)); &res->getattr[i].obj_attributes.attrmask, sizeof(bitmap4));
nfs41_name_cache_insert(session_name_cache(session), nfs41_name_cache_insert(session_name_cache(session),
path, args->lookup[i].name, &res->file[i].fh, 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 (i == count-1) {
if (target_out) if (target_out)

View file

@ -69,9 +69,10 @@ struct attr_cache_entry {
uint32_t time_modify_ns; uint32_t time_modify_ns;
uint32_t numlinks; uint32_t numlinks;
uint32_t mode; uint32_t mode;
unsigned short ref_count; unsigned ref_count : 26;
unsigned char type; unsigned type : 4;
unsigned char invalidated; unsigned invalidated : 1;
unsigned delegated : 1;
}; };
#define ATTR_ENTRY_SIZE sizeof(struct attr_cache_entry) #define ATTR_ENTRY_SIZE sizeof(struct attr_cache_entry)
@ -245,7 +246,8 @@ out_err_free:
static void attr_cache_update( static void attr_cache_update(
IN struct attr_cache_entry *entry, 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 */ /* update the attributes present in mask */
if (info->attrmask.count >= 1) { if (info->attrmask.count >= 1) {
@ -277,6 +279,9 @@ static void attr_cache_update(
entry->time_modify_ns = info->time_modify.nseconds; entry->time_modify_ns = info->time_modify.nseconds;
} }
} }
if (delegation == OPEN_DELEGATE_READ || delegation == OPEN_DELEGATE_WRITE)
entry->delegated = TRUE;
} }
static void copy_attrs( static void copy_attrs(
@ -430,15 +435,18 @@ static void name_cache_entry_refresh(
/* update the expiration timer */ /* update the expiration timer */
entry->expiration = time(NULL) + cache->expiration; entry->expiration = time(NULL) + cache->expiration;
/* move the entry to the front of cache->exp_entries */ /* move the entry to the front of cache->exp_entries */
list_remove(&entry->exp_entry); if (!list_empty(&entry->exp_entry)) {
list_add_head(&cache->exp_entries, &entry->exp_entry); list_remove(&entry->exp_entry);
list_add_head(&cache->exp_entries, &entry->exp_entry);
}
} }
static int name_cache_entry_update( static int name_cache_entry_update(
IN struct nfs41_name_cache *cache, IN struct nfs41_name_cache *cache,
IN struct name_cache_entry *entry, IN struct name_cache_entry *entry,
IN OPTIONAL const nfs41_fh *fh, 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; int status = NO_ERROR;
@ -453,8 +461,17 @@ static int name_cache_entry_update(
status = attr_cache_find_or_create(&cache->attributes, status = attr_cache_find_or_create(&cache->attributes,
info->fileid, &entry->attributes); info->fileid, &entry->attributes);
if (status == NO_ERROR) if (status == NO_ERROR) {
attr_cache_update(entry->attributes, info); 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) { } else if (entry->attributes) {
/* positive -> negative entry, deref the attributes */ /* positive -> negative entry, deref the attributes */
attr_cache_entry_deref(&cache->attributes, entry->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); dprintf(NCLVL1, "name_cache_entry_invalidate('%s')\n", entry->component);
if (entry->attributes) { 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 */ * if another entry attempts to use them */
entry->attributes->invalidated = 1; entry->attributes->invalidated = 1;
} }
@ -530,7 +547,7 @@ static int entry_invis(
OUT OPTIONAL bool_t *is_negative) OUT OPTIONAL bool_t *is_negative)
{ {
/* name entry timer expired? */ /* 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); dprintf(NCLVL2, "name_entry_expired('%s')\n", entry->component);
return 1; return 1;
} }
@ -814,7 +831,7 @@ int nfs41_attr_cache_update(
goto out_unlock; goto out_unlock;
} }
attr_cache_update(entry, info); attr_cache_update(entry, info, OPEN_DELEGATE_NONE);
out_unlock: out_unlock:
ReleaseSRWLockExclusive(&cache->lock); ReleaseSRWLockExclusive(&cache->lock);
@ -829,7 +846,8 @@ int nfs41_name_cache_insert(
IN const nfs41_component *name, IN const nfs41_component *name,
IN OPTIONAL const nfs41_fh *fh, IN OPTIONAL const nfs41_fh *fh,
IN OPTIONAL const nfs41_file_info *info, 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; struct name_cache_entry *grandparent, *parent, *target;
int status; int status;
@ -851,28 +869,29 @@ int nfs41_name_cache_insert(
const nfs41_component name = { "ROOT", 4 }; const nfs41_component name = { "ROOT", 4 };
status = name_cache_entry_create(cache, &name, &cache->root); status = name_cache_entry_create(cache, &name, &cache->root);
if (status) if (status)
goto out_unlock; goto out_err_deleg;
} }
status = name_cache_entry_update(cache, cache->root, fh, info); status = name_cache_entry_update(cache,
goto out_unlock; cache->root, fh, info, delegation);
goto out_err_deleg;
} }
status = name_cache_lookup(cache, 0, path, name->name, status = name_cache_lookup(cache, 0, path, name->name,
NULL, &grandparent, &parent, NULL); NULL, &grandparent, &parent, NULL);
if (status) if (status)
goto out_unlock; goto out_err_deleg;
if (cinfo && name_cache_entry_changed(cache, parent, cinfo)) { if (cinfo && name_cache_entry_changed(cache, parent, cinfo)) {
name_cache_entry_invalidate(cache, parent); name_cache_entry_invalidate(cache, parent);
goto out_unlock; goto out_err_deleg;
} }
status = name_cache_find_or_create(cache, parent, name, &target); status = name_cache_find_or_create(cache, parent, name, &target);
if (status) 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: out_unlock:
ReleaseSRWLockExclusive(&cache->lock); ReleaseSRWLockExclusive(&cache->lock);
@ -880,6 +899,66 @@ out_unlock:
dprintf(NCLVL1, "<-- nfs41_name_cache_insert() returning %d\n", dprintf(NCLVL1, "<-- nfs41_name_cache_insert() returning %d\n",
status); status);
return 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( int nfs41_name_cache_remove(
@ -917,7 +996,7 @@ int nfs41_name_cache_remove(
target->attributes->numlinks--; target->attributes->numlinks--;
/* make this a negative entry and unlink children */ /* 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); name_cache_unlink_children_recursive(cache, target);
out_unlock: out_unlock:
@ -1005,7 +1084,7 @@ int nfs41_name_cache_rename(
if (status) if (status)
goto out_unlock; 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); name_cache_unlink_children_recursive(cache, src);
out_unlock: out_unlock:

View file

@ -75,7 +75,14 @@ int nfs41_name_cache_insert(
IN const nfs41_component *name, IN const nfs41_component *name,
IN OPTIONAL const nfs41_fh *fh, IN OPTIONAL const nfs41_fh *fh,
IN OPTIONAL const nfs41_file_info *info, 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( int nfs41_name_cache_remove(
IN struct nfs41_name_cache *cache, IN struct nfs41_name_cache *cache,

View file

@ -458,7 +458,7 @@ int nfs41_rpc_open(
AcquireSRWLockShared(&file->path->lock); AcquireSRWLockShared(&file->path->lock);
nfs41_name_cache_insert(session_name_cache(session), nfs41_name_cache_insert(session_name_cache(session),
file->path->path, &file->name, &file->fh, file->path->path, &file->name, &file->fh,
info, &open_res.resok4.cinfo); info, &open_res.resok4.cinfo, delegation->type);
ReleaseSRWLockShared(&file->path->lock); ReleaseSRWLockShared(&file->path->lock);
if (create == OPEN4_CREATE) if (create == OPEN4_CREATE)
@ -558,7 +558,7 @@ int nfs41_create(
AcquireSRWLockShared(&file->path->lock); AcquireSRWLockShared(&file->path->lock);
nfs41_name_cache_insert(session_name_cache(session), nfs41_name_cache_insert(session_name_cache(session),
file->path->path, &file->name, &file->fh, file->path->path, &file->name, &file->fh,
&file_info, &create_res.cinfo); &file_info, &create_res.cinfo, OPEN_DELEGATE_NONE);
ReleaseSRWLockShared(&file->path->lock); ReleaseSRWLockShared(&file->path->lock);
nfs41_superblock_space_changed(file->fh.superblock); nfs41_superblock_space_changed(file->fh.superblock);
@ -1401,7 +1401,7 @@ int nfs41_link(
AcquireSRWLockShared(&dst_dir->path->lock); AcquireSRWLockShared(&dst_dir->path->lock);
nfs41_name_cache_insert(session_name_cache(session), nfs41_name_cache_insert(session_name_cache(session),
dst_dir->path->path, target, &link_out->fh, 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); ReleaseSRWLockShared(&dst_dir->path->lock);
nfs41_superblock_space_changed(dst_dir->fh.superblock); nfs41_superblock_space_changed(dst_dir->fh.superblock);
@ -1562,7 +1562,13 @@ int nfs41_delegreturn(
if (status) if (status)
goto out; 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: out:
return status; return status;
} }