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 */
|
/* 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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue