NFS client updates for Linux 4.10
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 -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJYWoWvAAoJEGcL54qWCgDydigQAMFTUZTjHGx34l3yqie3uV0D P0Ws6qfQJwN6xwgbhLMt6pbECadN7d55KszIM71gu/Iqa1UbtHZht2Slf/Tw5wY8 vjptzLkvOie5g9sGIhhQqkgrXnG3A96aEuaknIj9JXWALJb01M94ZfC0STgUjmil sp100cDmmOonqflk7Tgh/jmfiUucBw9HnyNRY59sUaR0lAmHRrpJuqftmarYKRrq 1rTCeGx6MyM2kVyqGsY7FP1prQcNcIJXwti/EXrOywXbHZxmjl+l0WLu6iUOEj/I zvfWCeMFyMXeVsTrRLYeM1vQ/maUbSev6gms2RshbmDITE6Ir9nHfBTCfOmh95wV paKnAzuEKsUR+LhEbsORk03efQYkeDQuJW3QqhdVuqGnEwhaboTiP4GRJLjEo287 dHy6sEGEbAcieUsolXhDIaxggoF39gGihOT3+m+WgIlXRd38W2mvlQC9oaq89ehw Ipetm3swnkY8bTavsNYFW1x+V5zrGH9Dlu2/mpnqVAIwGT+ByolD8tYDAHf4zj3b cy9XhFzdLDRy4V95l4hzZFDCdjy4dZZu7cJEO5zqUB3236qhiZbGLjL232ZEHFi3 wNHn13nADV+DzoOuB5HJwfhKyOOBQsQpBIvzAgt1n7muZwxa35nX/2waX1xt2HX5 J+s+e02xJnMStcr/2O5v =8gLp -----END PGP SIGNATURE----- Merge tag 'nfs-for-4.10-2' of git://git.linux-nfs.org/projects/trondmy/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
This commit is contained in:
commit
bc1ecd626b
23
fs/nfs/dir.c
23
fs/nfs/dir.c
|
@ -1273,8 +1273,8 @@ out_error:
|
|||
*/
|
||||
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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
if (nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE))
|
||||
goto force_reval;
|
||||
if (nfs_attribute_timeout(inode))
|
||||
goto force_reval;
|
||||
out_noreval:
|
||||
return 0;
|
||||
force_reval:
|
||||
return __nfs_revalidate_inode(server, inode);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
@ -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;
|
||||
|
|
|
@ -177,7 +177,7 @@ out_err:
|
|||
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);
|
||||
|
|
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -1044,13 +1083,6 @@ out:
|
|||
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))
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
|
|
@ -494,21 +494,18 @@ nfs4_alloc_state_owner(struct nfs_server *server,
|
|||
}
|
||||
|
||||
static void
|
||||
nfs4_drop_state_owner(struct nfs4_state_owner *sp)
|
||||
nfs4_reset_state_owner(struct nfs4_state_owner *sp)
|
||||
{
|
||||
struct rb_node *rb_node = &sp->so_server_node;
|
||||
|
||||
if (!RB_EMPTY_NODE(rb_node)) {
|
||||
struct nfs_server *server = sp->so_server;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (!RB_EMPTY_NODE(rb_node)) {
|
||||
rb_erase(rb_node, &server->state_owners);
|
||||
RB_CLEAR_NODE(rb_node);
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
/* This state_owner is no longer usable, but must
|
||||
* remain in place so that state recovery can find it
|
||||
* and the opens associated with it.
|
||||
* It may also be used for new 'open' request to
|
||||
* return a delegation to the server.
|
||||
* So update the 'create_time' so that it looks like
|
||||
* a new state_owner. This will cause the server to
|
||||
* request an OPEN_CONFIRM to start a new sequence.
|
||||
*/
|
||||
sp->so_seqid.create_time = ktime_get();
|
||||
}
|
||||
|
||||
static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
|
||||
|
@ -797,21 +794,33 @@ void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
|
|||
|
||||
/*
|
||||
* Search the state->lock_states for an existing lock_owner
|
||||
* that is compatible with current->files
|
||||
* that is compatible with either of the given owners.
|
||||
* If the second is non-zero, then the first refers to a Posix-lock
|
||||
* owner (current->files) and the second refers to a flock/OFD
|
||||
* owner (struct file*). In that case, prefer a match for the first
|
||||
* owner.
|
||||
* If both sorts of locks are held on the one file we cannot know
|
||||
* which stateid was intended to be used, so a "correct" choice cannot
|
||||
* be made. Failing that, a "consistent" choice is preferable. The
|
||||
* consistent choice we make is to prefer the first owner, that of a
|
||||
* Posix lock.
|
||||
*/
|
||||
static struct nfs4_lock_state *
|
||||
__nfs4_find_lock_state(struct nfs4_state *state,
|
||||
fl_owner_t fl_owner, fl_owner_t fl_owner2)
|
||||
{
|
||||
struct nfs4_lock_state *pos;
|
||||
struct nfs4_lock_state *pos, *ret = NULL;
|
||||
list_for_each_entry(pos, &state->lock_states, ls_locks) {
|
||||
if (pos->ls_owner != fl_owner &&
|
||||
pos->ls_owner != fl_owner2)
|
||||
continue;
|
||||
atomic_inc(&pos->ls_count);
|
||||
return pos;
|
||||
if (pos->ls_owner == fl_owner) {
|
||||
ret = pos;
|
||||
break;
|
||||
}
|
||||
if (pos->ls_owner == fl_owner2)
|
||||
ret = pos;
|
||||
}
|
||||
return NULL;
|
||||
if (ret)
|
||||
atomic_inc(&ret->ls_count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1101,7 +1110,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
|
|||
|
||||
sp = container_of(seqid->sequence, struct nfs4_state_owner, so_seqid);
|
||||
if (status == -NFS4ERR_BAD_SEQID)
|
||||
nfs4_drop_state_owner(sp);
|
||||
nfs4_reset_state_owner(sp);
|
||||
if (!nfs4_has_session(sp->so_server->nfs_client))
|
||||
nfs_increment_seqid(status, seqid);
|
||||
}
|
||||
|
|
|
@ -502,11 +502,13 @@ static int nfs4_stat_to_errno(int);
|
|||
(compound_encode_hdr_maxsz + \
|
||||
encode_sequence_maxsz + \
|
||||
encode_putfh_maxsz + \
|
||||
encode_layoutreturn_maxsz + \
|
||||
encode_open_downgrade_maxsz)
|
||||
#define NFS4_dec_open_downgrade_sz \
|
||||
(compound_decode_hdr_maxsz + \
|
||||
decode_sequence_maxsz + \
|
||||
decode_putfh_maxsz + \
|
||||
decode_layoutreturn_maxsz + \
|
||||
decode_open_downgrade_maxsz)
|
||||
#define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \
|
||||
encode_sequence_maxsz + \
|
||||
|
@ -2277,9 +2279,9 @@ static void nfs4_xdr_enc_close(struct rpc_rqst *req, struct xdr_stream *xdr,
|
|||
encode_putfh(xdr, args->fh, &hdr);
|
||||
if (args->lr_args)
|
||||
encode_layoutreturn(xdr, args->lr_args, &hdr);
|
||||
encode_close(xdr, args, &hdr);
|
||||
if (args->bitmask != NULL)
|
||||
encode_getfattr(xdr, args->bitmask, &hdr);
|
||||
encode_close(xdr, args, &hdr);
|
||||
encode_nops(&hdr);
|
||||
}
|
||||
|
||||
|
@ -2356,6 +2358,8 @@ static void nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req,
|
|||
encode_compound_hdr(xdr, req, &hdr);
|
||||
encode_sequence(xdr, &args->seq_args, &hdr);
|
||||
encode_putfh(xdr, args->fh, &hdr);
|
||||
if (args->lr_args)
|
||||
encode_layoutreturn(xdr, args->lr_args, &hdr);
|
||||
encode_open_downgrade(xdr, args, &hdr);
|
||||
encode_nops(&hdr);
|
||||
}
|
||||
|
@ -2701,7 +2705,8 @@ static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
|
|||
encode_putfh(xdr, args->fhandle, &hdr);
|
||||
if (args->lr_args)
|
||||
encode_layoutreturn(xdr, args->lr_args, &hdr);
|
||||
encode_getfattr(xdr, args->bitmask, &hdr);
|
||||
if (args->bitmask)
|
||||
encode_getfattr(xdr, args->bitmask, &hdr);
|
||||
encode_delegreturn(xdr, args->stateid, &hdr);
|
||||
encode_nops(&hdr);
|
||||
}
|
||||
|
@ -6151,6 +6156,12 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
|
|||
status = decode_putfh(xdr);
|
||||
if (status)
|
||||
goto out;
|
||||
if (res->lr_res) {
|
||||
status = decode_layoutreturn(xdr, res->lr_res);
|
||||
res->lr_ret = status;
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
status = decode_open_downgrade(xdr, res);
|
||||
out:
|
||||
return status;
|
||||
|
@ -6484,16 +6495,12 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
|
|||
if (status)
|
||||
goto out;
|
||||
}
|
||||
if (res->fattr != NULL) {
|
||||
status = decode_getfattr(xdr, res->fattr, res->server);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
}
|
||||
status = decode_close(xdr, res);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
/*
|
||||
* Note: Server may do delete on close for this file
|
||||
* in which case the getattr call will fail with
|
||||
* an ESTALE error. Shouldn't be a problem,
|
||||
* though, since fattr->valid will remain unset.
|
||||
*/
|
||||
decode_getfattr(xdr, res->fattr, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
@ -6966,9 +6973,11 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
|
|||
if (status)
|
||||
goto out;
|
||||
}
|
||||
status = decode_getfattr(xdr, res->fattr, res->server);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
if (res->fattr) {
|
||||
status = decode_getfattr(xdr, res->fattr, res->server);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
}
|
||||
status = decode_delegreturn(xdr);
|
||||
out:
|
||||
return status;
|
||||
|
|
|
@ -1251,6 +1251,7 @@ bool pnfs_roc(struct inode *ino,
|
|||
nfs4_stateid stateid;
|
||||
enum pnfs_iomode iomode = 0;
|
||||
bool layoutreturn = false, roc = false;
|
||||
bool skip_read = false;
|
||||
|
||||
if (!nfs_have_layout(ino))
|
||||
return false;
|
||||
|
@ -1270,18 +1271,27 @@ retry:
|
|||
}
|
||||
|
||||
/* no roc if we hold a delegation */
|
||||
if (nfs4_check_delegation(ino, FMODE_READ))
|
||||
goto out_noroc;
|
||||
if (nfs4_check_delegation(ino, FMODE_READ)) {
|
||||
if (nfs4_check_delegation(ino, FMODE_WRITE))
|
||||
goto out_noroc;
|
||||
skip_read = true;
|
||||
}
|
||||
|
||||
list_for_each_entry(ctx, &nfsi->open_files, list) {
|
||||
state = ctx->state;
|
||||
if (state == NULL)
|
||||
continue;
|
||||
/* Don't return layout if there is open file state */
|
||||
if (state != NULL && state->state != 0)
|
||||
if (state->state & FMODE_WRITE)
|
||||
goto out_noroc;
|
||||
if (state->state & FMODE_READ)
|
||||
skip_read = true;
|
||||
}
|
||||
|
||||
|
||||
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) {
|
||||
if (skip_read && lseg->pls_range.iomode == IOMODE_READ)
|
||||
continue;
|
||||
/* If we are sending layoutreturn, invalidate all valid lsegs */
|
||||
if (!test_and_clear_bit(NFS_LSEG_ROC, &lseg->pls_flags))
|
||||
continue;
|
||||
|
|
|
@ -340,10 +340,8 @@ extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
|
|||
extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
|
||||
extern int nfs_permission(struct inode *, int);
|
||||
extern int nfs_open(struct inode *, struct file *);
|
||||
extern int nfs_attribute_timeout(struct inode *inode);
|
||||
extern int nfs_attribute_cache_expired(struct inode *inode);
|
||||
extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
|
||||
extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode);
|
||||
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
|
||||
extern bool nfs_mapping_need_revalidate_inode(struct inode *inode);
|
||||
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
|
||||
|
|
Loading…
Reference in New Issue