Skip to content

Commit

Permalink
Merge tag 'nfs-for-4.10-2' of git://git.linux-nfs.org/projects/trondm…
Browse files Browse the repository at this point in the history
…y/linux-nfs

Pull more NFS client updates from Trond Myklebust:
 "Highlights include:

   - further attribute cache improvements to make revalidation more fine
     grained

   - NFSv4 locking improvements

  Bugfixes:

   - nfs4_fl_prepare_ds must be careful about reporting success in files
     layout

   - pNFS/flexfiles: Instead of marking a device inactive, remove it
     from the cache"

* tag 'nfs-for-4.10-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4: Retry the DELEGRETURN if the embedded GETATTR is rejected with EACCES
  NFS: Retry the CLOSE if the embedded GETATTR is rejected with EACCES
  NFSv4: Place the GETATTR operation before the CLOSE
  NFSv4: Also ask for attributes when downgrading to a READ-only state
  NFS: Don't abuse NFS_INO_REVAL_FORCED in nfs_post_op_update_inode_locked()
  pNFS: Return RW layouts on OPEN_DOWNGRADE
  NFSv4: Add encode/decode of the layoutreturn op in OPEN_DOWNGRADE
  NFS: Don't disconnect open-owner on NFS4ERR_BAD_SEQID
  NFSv4: ensure __nfs4_find_lock_state returns consistent result.
  NFSv4.1: nfs4_fl_prepare_ds must be careful about reporting success.
  pNFS/flexfiles: delete deviceid, don't mark inactive
  NFS: Clean up nfs_attribute_timeout()
  NFS: Remove unused function nfs_revalidate_inode_rcu()
  NFS: Fix and clean up the access cache validity checking
  NFS: Only look at the change attribute cache state in nfs_weak_revalidate()
  NFS: Clean up cache validity checking
  NFS: Don't revalidate the file on close if we hold a delegation
  NFSv4: Don't discard the attributes returned by asynchronous DELEGRETURN
  NFSv4: Update the attribute cache info in update_changeattr
  • Loading branch information
torvalds committed Dec 21, 2016
2 parents d5db84a + 8ac2b42 commit bc1ecd6
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 111 deletions.
23 changes: 12 additions & 11 deletions fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1273,8 +1273,8 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
*/
static int nfs_weak_revalidate(struct dentry *dentry, unsigned int flags)
{
int error;
struct inode *inode = d_inode(dentry);
int error = 0;

/*
* I believe we can only get a negative dentry here in the case of a
Expand All @@ -1293,7 +1293,8 @@ static int nfs_weak_revalidate(struct dentry *dentry, unsigned int flags)
return 0;
}

error = nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (nfs_mapping_need_revalidate_inode(inode))
error = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
dfprintk(LOOKUPCACHE, "NFS: %s: inode %lu is %s\n",
__func__, inode->i_ino, error ? "invalid" : "valid");
return !error;
Expand Down Expand Up @@ -2285,8 +2286,7 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
if (cache == NULL)
goto out;
/* Found an entry, is our attribute cache valid? */
if (!nfs_attribute_cache_expired(inode) &&
!(nfsi->cache_validity & NFS_INO_INVALID_ATTR))
if (!nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS))
break;
err = -ECHILD;
if (!may_block)
Expand Down Expand Up @@ -2334,12 +2334,12 @@ static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred,
cache = NULL;
if (cache == NULL)
goto out;
err = nfs_revalidate_inode_rcu(NFS_SERVER(inode), inode);
if (err)
if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS))
goto out;
res->jiffies = cache->jiffies;
res->cred = cache->cred;
res->mask = cache->mask;
err = 0;
out:
rcu_read_unlock();
return err;
Expand Down Expand Up @@ -2491,12 +2491,13 @@ EXPORT_SYMBOL_GPL(nfs_may_open);
static int nfs_execute_ok(struct inode *inode, int mask)
{
struct nfs_server *server = NFS_SERVER(inode);
int ret;
int ret = 0;

if (mask & MAY_NOT_BLOCK)
ret = nfs_revalidate_inode_rcu(server, inode);
else
ret = nfs_revalidate_inode(server, inode);
if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS)) {
if (mask & MAY_NOT_BLOCK)
return -ECHILD;
ret = __nfs_revalidate_inode(server, inode);
}
if (ret == 0 && !execute_ok(inode))
ret = -EACCES;
return ret;
Expand Down
12 changes: 1 addition & 11 deletions fs/nfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,11 @@ EXPORT_SYMBOL_GPL(nfs_file_release);
static int nfs_revalidate_file_size(struct inode *inode, struct file *filp)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_inode *nfsi = NFS_I(inode);
const unsigned long force_reval = NFS_INO_REVAL_PAGECACHE|NFS_INO_REVAL_FORCED;
unsigned long cache_validity = nfsi->cache_validity;

if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) &&
(cache_validity & force_reval) != force_reval)
goto out_noreval;

if (filp->f_flags & O_DIRECT)
goto force_reval;
if (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
goto force_reval;
if (nfs_attribute_timeout(inode))
if (nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE))
goto force_reval;
out_noreval:
return 0;
force_reval:
return __nfs_revalidate_inode(server, inode);
Expand Down
3 changes: 2 additions & 1 deletion fs/nfs/filelayout/filelayoutdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
s->nfs_client->cl_minorversion);

out_test_devid:
if (filelayout_test_devid_unavailable(devid))
if (ret->ds_clp == NULL ||
filelayout_test_devid_unavailable(devid))
ret = NULL;
out:
return ret;
Expand Down
6 changes: 4 additions & 2 deletions fs/nfs/flexfilelayout/flexfilelayout.c
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,8 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
case -EPIPE:
dprintk("%s DS connection error %d\n", __func__,
task->tk_status);
nfs4_mark_deviceid_unavailable(devid);
nfs4_delete_deviceid(devid->ld, devid->nfs_client,
&devid->deviceid);
rpc_wake_up(&tbl->slot_tbl_waitq);
/* fall through */
default:
Expand Down Expand Up @@ -1175,7 +1176,8 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
default:
dprintk("%s DS connection error %d\n", __func__,
task->tk_status);
nfs4_mark_deviceid_unavailable(devid);
nfs4_delete_deviceid(devid->ld, devid->nfs_client,
&devid->deviceid);
}
/* FIXME: Need to prevent infinite looping here. */
return -NFS4ERR_RESET_TO_PNFS;
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/flexfilelayout/flexfilelayoutdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
static void ff_layout_mark_devid_invalid(struct pnfs_layout_segment *lseg,
struct nfs4_deviceid_node *devid)
{
nfs4_mark_deviceid_unavailable(devid);
nfs4_delete_deviceid(devid->ld, devid->nfs_client, &devid->deviceid);
if (!ff_layout_has_available_ds(lseg))
pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode,
lseg);
Expand Down
75 changes: 41 additions & 34 deletions fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,43 @@ int nfs_sync_mapping(struct address_space *mapping)
return ret;
}

static int nfs_attribute_timeout(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);

return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
}

static bool nfs_check_cache_invalid_delegated(struct inode *inode, unsigned long flags)
{
unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);

/* Special case for the pagecache or access cache */
if (flags == NFS_INO_REVAL_PAGECACHE &&
!(cache_validity & NFS_INO_REVAL_FORCED))
return false;
return (cache_validity & flags) != 0;
}

static bool nfs_check_cache_invalid_not_delegated(struct inode *inode, unsigned long flags)
{
unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);

if ((cache_validity & flags) != 0)
return true;
if (nfs_attribute_timeout(inode))
return true;
return false;
}

bool nfs_check_cache_invalid(struct inode *inode, unsigned long flags)
{
if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
return nfs_check_cache_invalid_delegated(inode, flags);

return nfs_check_cache_invalid_not_delegated(inode, flags);
}

static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
{
struct nfs_inode *nfsi = NFS_I(inode);
Expand Down Expand Up @@ -795,6 +832,8 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
if (!is_sync)
return;
inode = d_inode(ctx->dentry);
if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
return;
nfsi = NFS_I(inode);
if (inode->i_mapping->nrpages == 0)
return;
Expand Down Expand Up @@ -1044,13 +1083,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
return status;
}

int nfs_attribute_timeout(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);

return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
}

int nfs_attribute_cache_expired(struct inode *inode)
{
if (nfs_have_delegated_attributes(inode))
Expand All @@ -1073,15 +1105,6 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
}
EXPORT_SYMBOL_GPL(nfs_revalidate_inode);

int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode)
{
if (!(NFS_I(inode)->cache_validity &
(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
&& !nfs_attribute_cache_expired(inode))
return NFS_STALE(inode) ? -ESTALE : 0;
return -ECHILD;
}

static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
{
struct nfs_inode *nfsi = NFS_I(inode);
Expand Down Expand Up @@ -1114,17 +1137,8 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map

bool nfs_mapping_need_revalidate_inode(struct inode *inode)
{
unsigned long cache_validity = NFS_I(inode)->cache_validity;

if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) {
const unsigned long force_reval =
NFS_INO_REVAL_PAGECACHE|NFS_INO_REVAL_FORCED;
return (cache_validity & force_reval) == force_reval;
}

return (cache_validity & NFS_INO_REVAL_PAGECACHE)
|| nfs_attribute_timeout(inode)
|| NFS_STALE(inode);
return nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE) ||
NFS_STALE(inode);
}

int nfs_revalidate_mapping_rcu(struct inode *inode)
Expand Down Expand Up @@ -1536,13 +1550,6 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
{
unsigned long invalid = NFS_INO_INVALID_ATTR;

/*
* Don't revalidate the pagecache if we hold a delegation, but do
* force an attribute update
*/
if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
invalid = NFS_INO_INVALID_ATTR|NFS_INO_REVAL_FORCED;

if (S_ISDIR(inode->i_mode))
invalid |= NFS_INO_INVALID_DATA;
nfs_set_cache_invalid(inode, invalid);
Expand Down
1 change: 1 addition & 0 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ extern int nfs_drop_inode(struct inode *);
extern void nfs_clear_inode(struct inode *);
extern void nfs_evict_inode(struct inode *);
void nfs_zap_acl_cache(struct inode *inode);
extern bool nfs_check_cache_invalid(struct inode *, unsigned long);
extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
extern int nfs_wait_atomic_killable(atomic_t *p);

Expand Down
43 changes: 35 additions & 8 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1089,8 +1089,15 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)

spin_lock(&dir->i_lock);
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
if (!cinfo->atomic || cinfo->before != dir->i_version)
if (cinfo->atomic && cinfo->before == dir->i_version) {
nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
nfsi->attrtimeo_timestamp = jiffies;
} else {
nfs_force_lookup_revalidate(dir);
if (cinfo->before != dir->i_version)
nfsi->cache_validity |= NFS_INO_INVALID_ACCESS |
NFS_INO_INVALID_ACL;
}
dir->i_version = cinfo->after;
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
nfs_fscache_invalidate(dir);
Expand Down Expand Up @@ -3115,6 +3122,16 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
res_stateid = &calldata->res.stateid;
renew_lease(server, calldata->timestamp);
break;
case -NFS4ERR_ACCESS:
if (calldata->arg.bitmask != NULL) {
calldata->arg.bitmask = NULL;
calldata->res.fattr = NULL;
task->tk_status = 0;
rpc_restart_call_prepare(task);
goto out_release;

}
break;
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED:
Expand All @@ -3140,7 +3157,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
res_stateid, calldata->arg.fmode);
out_release:
nfs_release_seqid(calldata->arg.seqid);
nfs_refresh_inode(calldata->inode, calldata->res.fattr);
nfs_refresh_inode(calldata->inode, &calldata->fattr);
dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
}

Expand Down Expand Up @@ -3193,9 +3210,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
goto out_wait;
}

if (calldata->arg.fmode == 0) {
if (calldata->arg.fmode == 0)
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];

if (calldata->arg.fmode == 0 || calldata->arg.fmode == FMODE_READ) {
/* Close-to-open cache consistency revalidation */
if (!nfs4_have_delegation(inode, FMODE_READ))
calldata->arg.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
Expand All @@ -3207,7 +3225,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
nfs4_map_atomic_open_share(NFS_SERVER(inode),
calldata->arg.fmode, 0);

nfs_fattr_init(calldata->res.fattr);
if (calldata->res.fattr == NULL)
calldata->arg.bitmask = NULL;
else if (calldata->arg.bitmask == NULL)
calldata->res.fattr = NULL;
calldata->timestamp = jiffies;
if (nfs4_setup_sequence(NFS_SERVER(inode),
&calldata->arg.seq_args,
Expand Down Expand Up @@ -3274,6 +3295,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
calldata->arg.seqid = alloc_seqid(&state->owner->so_seqid, gfp_mask);
if (IS_ERR(calldata->arg.seqid))
goto out_free_calldata;
nfs_fattr_init(&calldata->fattr);
calldata->arg.fmode = 0;
calldata->lr.arg.ld_private = &calldata->lr.ld_private;
calldata->res.fattr = &calldata->fattr;
Expand Down Expand Up @@ -5673,6 +5695,14 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
case -NFS4ERR_STALE_STATEID:
task->tk_status = 0;
break;
case -NFS4ERR_ACCESS:
if (data->args.bitmask) {
data->args.bitmask = NULL;
data->res.fattr = NULL;
task->tk_status = 0;
rpc_restart_call_prepare(task);
return;
}
default:
if (nfs4_async_handle_error(task, data->res.server,
NULL, NULL) == -EAGAIN) {
Expand All @@ -5692,6 +5722,7 @@ static void nfs4_delegreturn_release(void *calldata)
if (data->lr.roc)
pnfs_roc_release(&data->lr.arg, &data->lr.res,
data->res.lr_ret);
nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
nfs_iput_and_deactive(inode);
}
kfree(calldata);
Expand Down Expand Up @@ -5780,10 +5811,6 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
if (status != 0)
goto out;
status = data->rpc_status;
if (status == 0)
nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
else
nfs_refresh_inode(inode, &data->fattr);
out:
rpc_put_task(task);
return status;
Expand Down
Loading

0 comments on commit bc1ecd6

Please sign in to comment.