Commit d8132e08 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-4.2-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
 "Highlights include:

  Stable patches:
   - Fix a situation where the client uses the wrong (zero) stateid.
   - Fix a memory leak in nfs_do_recoalesce

  Bugfixes:
   - Plug a memory leak when ->prepare_layoutcommit fails
   - Fix an Oops in the NFSv4 open code
   - Fix a backchannel deadlock
   - Fix a livelock in sunrpc when sendmsg fails due to low memory
     availability
   - Don't revalidate the mapping if both size and change attr are up to
     date
   - Ensure we don't miss a file extension when doing pNFS
   - Several fixes to handle NFSv4.1 sequence operation status bits
     correctly
   - Several pNFS layout return bugfixes"

* tag 'nfs-for-4.2-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (28 commits)
  nfs: Fix an oops caused by using other thread's stack space in ASYNC mode
  nfs: plug memory leak when ->prepare_layoutcommit fails
  SUNRPC: Report TCP errors to the caller
  sunrpc: translate -EAGAIN to -ENOBUFS when socket is writable.
  NFSv4.2: handle NFS-specific llseek errors
  NFS: Don't clear desc->pg_moreio in nfs_do_recoalesce()
  NFS: Fix a memory leak in nfs_do_recoalesce
  NFS: nfs_mark_for_revalidate should always set NFS_INO_REVAL_PAGECACHE
  NFS: Remove the "NFS_CAP_CHANGE_ATTR" capability
  NFS: Set NFS_INO_REVAL_PAGECACHE if the change attribute is uninitialised
  NFS: Don't revalidate the mapping if both size and change attr are up to date
  NFSv4/pnfs: Ensure we don't miss a file extension
  NFSv4: We must set NFS_OPEN_STATE flag in nfs_resync_open_stateid_locked
  SUNRPC: xprt_complete_bc_request must also decrement the free slot count
  SUNRPC: Fix a backchannel deadlock
  pNFS: Don't throw out valid layout segments
  pNFS: pnfs_roc_drain() fix a race with open
  pNFS: Fix races between return-on-close and layoutreturn.
  pNFS: pnfs_roc_drain should return 'true' when sleeping
  pNFS: Layoutreturn must invalidate all existing layout segments.
  ...
parents 2ee6b000 a49c2691
...@@ -775,7 +775,7 @@ static int nfs_init_server(struct nfs_server *server, ...@@ -775,7 +775,7 @@ static int nfs_init_server(struct nfs_server *server,
server->options = data->options; server->options = data->options;
server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID| server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP| NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME|NFS_CAP_CHANGE_ATTR; NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
if (data->rsize) if (data->rsize)
server->rsize = nfs_block_size(data->rsize, NULL); server->rsize = nfs_block_size(data->rsize, NULL);
......
...@@ -1852,7 +1852,7 @@ ff_layout_mirror_prepare_stats(struct nfs42_layoutstat_args *args, ...@@ -1852,7 +1852,7 @@ ff_layout_mirror_prepare_stats(struct nfs42_layoutstat_args *args,
struct nfs42_layoutstat_devinfo *devinfo; struct nfs42_layoutstat_devinfo *devinfo;
int i; int i;
for (i = 0; i <= FF_LAYOUT_MIRROR_COUNT(pls); i++) { for (i = 0; i < FF_LAYOUT_MIRROR_COUNT(pls); i++) {
if (*dev_count >= dev_limit) if (*dev_count >= dev_limit)
break; break;
mirror = FF_LAYOUT_COMP(pls, i); mirror = FF_LAYOUT_COMP(pls, i);
......
...@@ -442,8 +442,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st ...@@ -442,8 +442,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
if (fattr->valid & NFS_ATTR_FATTR_CHANGE) if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
inode->i_version = fattr->change_attr; inode->i_version = fattr->change_attr;
else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR)) else
nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR); nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_PAGECACHE);
if (fattr->valid & NFS_ATTR_FATTR_SIZE) if (fattr->valid & NFS_ATTR_FATTR_SIZE)
inode->i_size = nfs_size_to_loff_t(fattr->size); inode->i_size = nfs_size_to_loff_t(fattr->size);
else else
...@@ -1244,9 +1245,11 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat ...@@ -1244,9 +1245,11 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
if (fattr->valid & NFS_ATTR_FATTR_SIZE) { if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
cur_size = i_size_read(inode); cur_size = i_size_read(inode);
new_isize = nfs_size_to_loff_t(fattr->size); new_isize = nfs_size_to_loff_t(fattr->size);
if (cur_size != new_isize && nfsi->nrequests == 0) if (cur_size != new_isize)
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
} }
if (nfsi->nrequests != 0)
invalid &= ~NFS_INO_REVAL_PAGECACHE;
/* Have any file permissions changed? */ /* Have any file permissions changed? */
if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
...@@ -1684,13 +1687,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1684,13 +1687,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
invalid |= NFS_INO_INVALID_ATTR invalid |= NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_DATA | NFS_INO_INVALID_DATA
| NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL | NFS_INO_INVALID_ACL;
| NFS_INO_REVAL_PAGECACHE;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
nfs_force_lookup_revalidate(inode); nfs_force_lookup_revalidate(inode);
inode->i_version = fattr->change_attr; inode->i_version = fattr->change_attr;
} }
} else if (server->caps & NFS_CAP_CHANGE_ATTR) } else
nfsi->cache_validity |= save_cache_validity; nfsi->cache_validity |= save_cache_validity;
if (fattr->valid & NFS_ATTR_FATTR_MTIME) { if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
...@@ -1717,7 +1719,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1717,7 +1719,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if ((nfsi->nrequests == 0) || new_isize > cur_isize) { if ((nfsi->nrequests == 0) || new_isize > cur_isize) {
i_size_write(inode, new_isize); i_size_write(inode, new_isize);
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
invalid &= ~NFS_INO_REVAL_PAGECACHE;
} }
dprintk("NFS: isize change on server for file %s/%ld " dprintk("NFS: isize change on server for file %s/%ld "
"(%Ld to %Ld)\n", "(%Ld to %Ld)\n",
......
...@@ -296,6 +296,22 @@ extern struct rpc_procinfo nfs4_procedures[]; ...@@ -296,6 +296,22 @@ extern struct rpc_procinfo nfs4_procedures[];
#ifdef CONFIG_NFS_V4_SECURITY_LABEL #ifdef CONFIG_NFS_V4_SECURITY_LABEL
extern struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags); extern struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags);
static inline struct nfs4_label *
nfs4_label_copy(struct nfs4_label *dst, struct nfs4_label *src)
{
if (!dst || !src)
return NULL;
if (src->len > NFS4_MAXLABELLEN)
return NULL;
dst->lfs = src->lfs;
dst->pi = src->pi;
dst->len = src->len;
memcpy(dst->label, src->label, src->len);
return dst;
}
static inline void nfs4_label_free(struct nfs4_label *label) static inline void nfs4_label_free(struct nfs4_label *label)
{ {
if (label) { if (label) {
...@@ -316,6 +332,11 @@ static inline void nfs4_label_free(void *label) {} ...@@ -316,6 +332,11 @@ static inline void nfs4_label_free(void *label) {}
static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi) static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi)
{ {
} }
static inline struct nfs4_label *
nfs4_label_copy(struct nfs4_label *dst, struct nfs4_label *src)
{
return NULL;
}
#endif /* CONFIG_NFS_V4_SECURITY_LABEL */ #endif /* CONFIG_NFS_V4_SECURITY_LABEL */
/* proc.c */ /* proc.c */
......
...@@ -135,7 +135,7 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) ...@@ -135,7 +135,7 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
return err; return err;
} }
loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) static loff_t _nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
{ {
struct inode *inode = file_inode(filep); struct inode *inode = file_inode(filep);
struct nfs42_seek_args args = { struct nfs42_seek_args args = {
...@@ -171,6 +171,23 @@ loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) ...@@ -171,6 +171,23 @@ loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes); return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
} }
loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
{
struct nfs_server *server = NFS_SERVER(file_inode(filep));
struct nfs4_exception exception = { };
int err;
do {
err = _nfs42_proc_llseek(filep, offset, whence);
if (err == -ENOTSUPP)
return -EOPNOTSUPP;
err = nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
return err;
}
static void static void
nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata) nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
{ {
......
...@@ -467,7 +467,10 @@ static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp) ...@@ -467,7 +467,10 @@ static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
static void renew_lease(const struct nfs_server *server, unsigned long timestamp) static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
{ {
do_renew_lease(server->nfs_client, timestamp); struct nfs_client *clp = server->nfs_client;
if (!nfs4_has_session(clp))
do_renew_lease(clp, timestamp);
} }
struct nfs4_call_sync_data { struct nfs4_call_sync_data {
...@@ -616,8 +619,7 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) ...@@ -616,8 +619,7 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
clp = session->clp; clp = session->clp;
do_renew_lease(clp, res->sr_timestamp); do_renew_lease(clp, res->sr_timestamp);
/* Check sequence flags */ /* Check sequence flags */
if (res->sr_status_flags != 0) nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
nfs4_schedule_lease_recovery(clp);
nfs41_update_target_slotid(slot->table, slot, res); nfs41_update_target_slotid(slot->table, slot, res);
break; break;
case 1: case 1:
...@@ -910,6 +912,7 @@ struct nfs4_opendata { ...@@ -910,6 +912,7 @@ struct nfs4_opendata {
struct nfs_open_confirmres c_res; struct nfs_open_confirmres c_res;
struct nfs4_string owner_name; struct nfs4_string owner_name;
struct nfs4_string group_name; struct nfs4_string group_name;
struct nfs4_label *a_label;
struct nfs_fattr f_attr; struct nfs_fattr f_attr;
struct nfs4_label *f_label; struct nfs4_label *f_label;
struct dentry *dir; struct dentry *dir;
...@@ -1013,6 +1016,10 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, ...@@ -1013,6 +1016,10 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
if (IS_ERR(p->f_label)) if (IS_ERR(p->f_label))
goto err_free_p; goto err_free_p;
p->a_label = nfs4_label_alloc(server, gfp_mask);
if (IS_ERR(p->a_label))
goto err_free_f;
alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid; alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
p->o_arg.seqid = alloc_seqid(&sp->so_seqid, gfp_mask); p->o_arg.seqid = alloc_seqid(&sp->so_seqid, gfp_mask);
if (IS_ERR(p->o_arg.seqid)) if (IS_ERR(p->o_arg.seqid))
...@@ -1041,7 +1048,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, ...@@ -1041,7 +1048,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->o_arg.server = server; p->o_arg.server = server;
p->o_arg.bitmask = nfs4_bitmask(server, label); p->o_arg.bitmask = nfs4_bitmask(server, label);
p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0]; p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
p->o_arg.label = label; p->o_arg.label = nfs4_label_copy(p->a_label, label);
p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim); p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
switch (p->o_arg.claim) { switch (p->o_arg.claim) {
case NFS4_OPEN_CLAIM_NULL: case NFS4_OPEN_CLAIM_NULL:
...@@ -1074,6 +1081,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, ...@@ -1074,6 +1081,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
return p; return p;
err_free_label: err_free_label:
nfs4_label_free(p->a_label);
err_free_f:
nfs4_label_free(p->f_label); nfs4_label_free(p->f_label);
err_free_p: err_free_p:
kfree(p); kfree(p);
...@@ -1093,6 +1102,7 @@ static void nfs4_opendata_free(struct kref *kref) ...@@ -1093,6 +1102,7 @@ static void nfs4_opendata_free(struct kref *kref)
nfs4_put_open_state(p->state); nfs4_put_open_state(p->state);
nfs4_put_state_owner(p->owner); nfs4_put_state_owner(p->owner);
nfs4_label_free(p->a_label);
nfs4_label_free(p->f_label); nfs4_label_free(p->f_label);
dput(p->dir); dput(p->dir);
...@@ -1198,12 +1208,15 @@ static bool nfs_need_update_open_stateid(struct nfs4_state *state, ...@@ -1198,12 +1208,15 @@ static bool nfs_need_update_open_stateid(struct nfs4_state *state,
static void nfs_resync_open_stateid_locked(struct nfs4_state *state) static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
{ {
if (!(state->n_wronly || state->n_rdonly || state->n_rdwr))
return;
if (state->n_wronly) if (state->n_wronly)
set_bit(NFS_O_WRONLY_STATE, &state->flags); set_bit(NFS_O_WRONLY_STATE, &state->flags);
if (state->n_rdonly) if (state->n_rdonly)
set_bit(NFS_O_RDONLY_STATE, &state->flags); set_bit(NFS_O_RDONLY_STATE, &state->flags);
if (state->n_rdwr) if (state->n_rdwr)
set_bit(NFS_O_RDWR_STATE, &state->flags); set_bit(NFS_O_RDWR_STATE, &state->flags);
set_bit(NFS_OPEN_STATE, &state->flags);
} }
static void nfs_clear_open_stateid_locked(struct nfs4_state *state, static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
...@@ -7571,13 +7584,8 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) ...@@ -7571,13 +7584,8 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
goto out; goto out;
} }
ret = rpc_wait_for_completion_task(task); ret = rpc_wait_for_completion_task(task);
if (!ret) { if (!ret)
struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
if (task->tk_status == 0)
nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
ret = task->tk_status; ret = task->tk_status;
}
rpc_put_task(task); rpc_put_task(task);
out: out:
dprintk("<-- %s status=%d\n", __func__, ret); dprintk("<-- %s status=%d\n", __func__, ret);
...@@ -7965,16 +7973,17 @@ static void nfs4_layoutreturn_release(void *calldata) ...@@ -7965,16 +7973,17 @@ static void nfs4_layoutreturn_release(void *calldata)
{ {
struct nfs4_layoutreturn *lrp = calldata; struct nfs4_layoutreturn *lrp = calldata;
struct pnfs_layout_hdr *lo = lrp->args.layout; struct pnfs_layout_hdr *lo = lrp->args.layout;
LIST_HEAD(freeme);
dprintk("--> %s\n", __func__); dprintk("--> %s\n", __func__);
spin_lock(&lo->plh_inode->i_lock); spin_lock(&lo->plh_inode->i_lock);
if (lrp->res.lrs_present) if (lrp->res.lrs_present)
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range);
pnfs_clear_layoutreturn_waitbit(lo); pnfs_clear_layoutreturn_waitbit(lo);
clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
lo->plh_block_lgets--; lo->plh_block_lgets--;
spin_unlock(&lo->plh_inode->i_lock); spin_unlock(&lo->plh_inode->i_lock);
pnfs_free_lseg_list(&freeme);
pnfs_put_layout_hdr(lrp->args.layout); pnfs_put_layout_hdr(lrp->args.layout);
nfs_iput_and_deactive(lrp->inode); nfs_iput_and_deactive(lrp->inode);
kfree(calldata); kfree(calldata);
...@@ -8588,7 +8597,6 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { ...@@ -8588,7 +8597,6 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
.minor_version = 0, .minor_version = 0,
.init_caps = NFS_CAP_READDIRPLUS .init_caps = NFS_CAP_READDIRPLUS
| NFS_CAP_ATOMIC_OPEN | NFS_CAP_ATOMIC_OPEN
| NFS_CAP_CHANGE_ATTR
| NFS_CAP_POSIX_LOCK, | NFS_CAP_POSIX_LOCK,
.init_client = nfs40_init_client, .init_client = nfs40_init_client,
.shutdown_client = nfs40_shutdown_client, .shutdown_client = nfs40_shutdown_client,
...@@ -8614,7 +8622,6 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { ...@@ -8614,7 +8622,6 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
.minor_version = 1, .minor_version = 1,
.init_caps = NFS_CAP_READDIRPLUS .init_caps = NFS_CAP_READDIRPLUS
| NFS_CAP_ATOMIC_OPEN | NFS_CAP_ATOMIC_OPEN
| NFS_CAP_CHANGE_ATTR
| NFS_CAP_POSIX_LOCK | NFS_CAP_POSIX_LOCK
| NFS_CAP_STATEID_NFSV41 | NFS_CAP_STATEID_NFSV41
| NFS_CAP_ATOMIC_OPEN_V1, | NFS_CAP_ATOMIC_OPEN_V1,
...@@ -8637,7 +8644,6 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { ...@@ -8637,7 +8644,6 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
.minor_version = 2, .minor_version = 2,
.init_caps = NFS_CAP_READDIRPLUS .init_caps = NFS_CAP_READDIRPLUS
| NFS_CAP_ATOMIC_OPEN | NFS_CAP_ATOMIC_OPEN
| NFS_CAP_CHANGE_ATTR
| NFS_CAP_POSIX_LOCK | NFS_CAP_POSIX_LOCK
| NFS_CAP_STATEID_NFSV41 | NFS_CAP_STATEID_NFSV41
| NFS_CAP_ATOMIC_OPEN_V1 | NFS_CAP_ATOMIC_OPEN_V1
......
...@@ -2191,25 +2191,35 @@ static void nfs41_handle_server_reboot(struct nfs_client *clp) ...@@ -2191,25 +2191,35 @@ static void nfs41_handle_server_reboot(struct nfs_client *clp)
} }
} }
static void nfs41_handle_state_revoked(struct nfs_client *clp) static void nfs41_handle_all_state_revoked(struct nfs_client *clp)
{ {
nfs4_reset_all_state(clp); nfs4_reset_all_state(clp);
dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname); dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname);
} }
static void nfs41_handle_some_state_revoked(struct nfs_client *clp)
{
nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
nfs4_schedule_state_manager(clp);
dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname);
}
static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp) static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
{ {
/* This will need to handle layouts too */ /* FIXME: For now, we destroy all layouts. */
nfs_expire_all_delegations(clp); pnfs_destroy_all_layouts(clp);
/* FIXME: For now, we test all delegations+open state+locks. */
nfs41_handle_some_state_revoked(clp);
dprintk("%s: Recallable state revoked on server %s!\n", __func__, dprintk("%s: Recallable state revoked on server %s!\n", __func__,
clp->cl_hostname); clp->cl_hostname);
} }
static void nfs41_handle_backchannel_fault(struct nfs_client *clp) static void nfs41_handle_backchannel_fault(struct nfs_client *clp)
{ {
nfs_expire_all_delegations(clp); set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0) nfs4_schedule_state_manager(clp);
nfs4_schedule_state_manager(clp);
dprintk("%s: server %s declared a backchannel fault\n", __func__, dprintk("%s: server %s declared a backchannel fault\n", __func__,
clp->cl_hostname); clp->cl_hostname);
} }
...@@ -2231,10 +2241,11 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) ...@@ -2231,10 +2241,11 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
nfs41_handle_server_reboot(clp); nfs41_handle_server_reboot(clp);
if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED))
SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | nfs41_handle_all_state_revoked(clp);
if (flags & (SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
SEQ4_STATUS_ADMIN_STATE_REVOKED)) SEQ4_STATUS_ADMIN_STATE_REVOKED))
nfs41_handle_state_revoked(clp); nfs41_handle_some_state_revoked(clp);
if (flags & SEQ4_STATUS_LEASE_MOVED) if (flags & SEQ4_STATUS_LEASE_MOVED)
nfs4_schedule_lease_moved_recovery(clp); nfs4_schedule_lease_moved_recovery(clp);
if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
......
...@@ -1100,8 +1100,6 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) ...@@ -1100,8 +1100,6 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
mirror->pg_base = 0; mirror->pg_base = 0;
mirror->pg_recoalesce = 0; mirror->pg_recoalesce = 0;
desc->pg_moreio = 0;
while (!list_empty(&head)) { while (!list_empty(&head)) {
struct nfs_page *req; struct nfs_page *req;
...@@ -1109,8 +1107,11 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) ...@@ -1109,8 +1107,11 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
nfs_list_remove_request(req); nfs_list_remove_request(req);
if (__nfs_pageio_add_request(desc, req)) if (__nfs_pageio_add_request(desc, req))
continue; continue;
if (desc->pg_error < 0) if (desc->pg_error < 0) {
list_splice_tail(&head, &mirror->pg_list);
mirror->pg_recoalesce = 1;
return 0; return 0;
}
break; break;
} }
} while (mirror->pg_recoalesce); } while (mirror->pg_recoalesce);
......
...@@ -352,7 +352,7 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo, ...@@ -352,7 +352,7 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
{ {
struct pnfs_layout_segment *s; struct pnfs_layout_segment *s;
if (!test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags)) if (!test_and_clear_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
return false; return false;
list_for_each_entry(s, &lo->plh_segs, pls_list) list_for_each_entry(s, &lo->plh_segs, pls_list)
...@@ -362,6 +362,18 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo, ...@@ -362,6 +362,18 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
return true; return true;
} }
static bool
pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
{
if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
return false;
lo->plh_return_iomode = 0;
lo->plh_block_lgets++;
pnfs_get_layout_hdr(lo);
clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
return true;
}
static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg, static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
struct pnfs_layout_hdr *lo, struct inode *inode) struct pnfs_layout_hdr *lo, struct inode *inode)
{ {
...@@ -372,17 +384,16 @@ static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg, ...@@ -372,17 +384,16 @@ static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
if (pnfs_layout_need_return(lo, lseg)) { if (pnfs_layout_need_return(lo, lseg)) {
nfs4_stateid stateid; nfs4_stateid stateid;
enum pnfs_iomode iomode; enum pnfs_iomode iomode;
bool send;
stateid = lo->plh_stateid; stateid = lo->plh_stateid;
iomode = lo->plh_return_iomode; iomode = lo->plh_return_iomode;
/* decreased in pnfs_send_layoutreturn() */ send = pnfs_prepare_layoutreturn(lo);
lo->plh_block_lgets++;
lo->plh_return_iomode = 0;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
pnfs_get_layout_hdr(lo); if (send) {
/* Send an async layoutreturn so we dont deadlock */
/* Send an async layoutreturn so we dont deadlock */ pnfs_send_layoutreturn(lo, stateid, iomode, false);
pnfs_send_layoutreturn(lo, stateid, iomode, false); }
} else } else
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
...@@ -411,6 +422,10 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg) ...@@ -411,6 +422,10 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
pnfs_layoutreturn_before_put_lseg(lseg, lo, inode); pnfs_layoutreturn_before_put_lseg(lseg, lo, inode);
if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) { if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
spin_unlock(&inode->i_lock);
return;
}
pnfs_get_layout_hdr(lo); pnfs_get_layout_hdr(lo);
pnfs_layout_remove_lseg(lo, lseg); pnfs_layout_remove_lseg(lo, lseg);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
...@@ -451,6 +466,8 @@ pnfs_put_lseg_locked(struct pnfs_layout_segment *lseg) ...@@ -451,6 +466,8 @@ pnfs_put_lseg_locked(struct pnfs_layout_segment *lseg)
test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
if (atomic_dec_and_test(&lseg->pls_refcount)) { if (atomic_dec_and_test(&lseg->pls_refcount)) {
struct pnfs_layout_hdr *lo = lseg->pls_layout; struct pnfs_layout_hdr *lo = lseg->pls_layout;
if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags))
return;
pnfs_get_layout_hdr(lo); pnfs_get_layout_hdr(lo);
pnfs_layout_remove_lseg(lo, lseg); pnfs_layout_remove_lseg(lo, lseg);
pnfs_free_lseg_async(lseg); pnfs_free_lseg_async(lseg);
...@@ -924,6 +941,7 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo) ...@@ -924,6 +941,7 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
clear_bit_unlock(NFS_LAYOUT_RETURN, &lo->plh_flags); clear_bit_unlock(NFS_LAYOUT_RETURN, &lo->plh_flags);
smp_mb__after_atomic(); smp_mb__after_atomic();
wake_up_bit(&lo->plh_flags, NFS_LAYOUT_RETURN); wake_up_bit(&lo->plh_flags, NFS_LAYOUT_RETURN);
rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
} }
static int static int
...@@ -978,6 +996,7 @@ _pnfs_return_layout(struct inode *ino) ...@@ -978,6 +996,7 @@ _pnfs_return_layout(struct inode *ino)
LIST_HEAD(tmp_list); LIST_HEAD(tmp_list);
nfs4_stateid stateid; nfs4_stateid stateid;
int status = 0, empty; int status = 0, empty;
bool send;
dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino); dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino);
...@@ -1007,17 +1026,18 @@ _pnfs_return_layout(struct inode *ino) ...@@ -1007,17 +1026,18 @@ _pnfs_return_layout(struct inode *ino)
/* Don't send a LAYOUTRETURN if list was initially empty */ /* Don't send a LAYOUTRETURN if list was initially empty */
if (empty) { if (empty) {
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
pnfs_put_layout_hdr(lo);
dprintk("NFS: %s no layout segments to return\n", __func__); dprintk("NFS: %s no layout segments to return\n", __func__);
goto out; goto out_put_layout_hdr;
} }
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
lo->plh_block_lgets++; send = pnfs_prepare_layoutreturn(lo);
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
pnfs_free_lseg_list(&tmp_list); pnfs_free_lseg_list(&tmp_list);
if (send)
status = pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true); status = pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true);
out_put_layout_hdr:
pnfs_put_layout_hdr(lo);
out: out:
dprintk("<-- %s status: %d\n", __func__, status); dprintk("<-- %s status: %d\n", __func__, status);
return status; return status;
...@@ -1097,13 +1117,9 @@ bool pnfs_roc(struct inode *ino) ...@@ -1097,13 +1117,9 @@ bool pnfs_roc(struct inode *ino)
out_noroc: out_noroc:
if (lo) { if (lo) {
stateid = lo->plh_stateid; stateid = lo->plh_stateid;
layoutreturn = if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags))
&lo->plh_flags); layoutreturn = pnfs_prepare_layoutreturn(lo);
if (layoutreturn) {
lo->plh_block_lgets++;
pnfs_get_layout_hdr(lo);
}
} }
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
if (layoutreturn) { if (layoutreturn) {
...@@ -1146,15 +1162,18 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task) ...@@ -1146,15 +1162,18 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
struct pnfs_layout_segment *lseg; struct pnfs_layout_segment *lseg;
nfs4_stateid stateid; nfs4_stateid stateid;
u32 current_seqid; u32 current_seqid;
bool found = false, layoutreturn = false; bool layoutreturn = false;
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list) list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list) {
if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) { if (!test_bit(NFS_LSEG_ROC, &lseg->pls_flags))
rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL); continue;
found = true; if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags))
goto out; continue;
} rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
spin_unlock(&ino->i_lock);
return true;
}
lo = nfsi->layout; lo = nfsi->layout;
current_seqid = be32_to_cpu(lo->plh_stateid.seqid); current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
...@@ -1162,23 +1181,19 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task) ...@@ -1162,23 +1181,19 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
* a barrier, we choose the worst-case barrier. * a barrier, we choose the worst-case barrier.
*/ */
*barrier = current_seqid + atomic_read(&lo->plh_outstanding); *barrier = current_seqid + atomic_read(&lo->plh_outstanding);
out: stateid = lo->plh_stateid;
if (!found) { if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
stateid = lo->plh_stateid; &lo->plh_flags))
layoutreturn = layoutreturn = pnfs_prepare_layoutreturn(lo);
test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, if (test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
&lo->plh_flags); rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
if (layoutreturn) {
lo->plh_block_lgets++;
pnfs_get_layout_hdr(lo);
}
}
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
if (layoutreturn) { if (layoutreturn) {
rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, false); pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, false);
return true;
} }
return found; return false;
} }
/* /*
...@@ -1695,7 +1710,6 @@ void pnfs_error_mark_layout_for_return(struct inode *inode, ...@@ -1695,7 +1710,6 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
/* set failure bit so that pnfs path will be retried later */ /* set failure bit so that pnfs path will be retried later */
pnfs_layout_set_fail_bit(lo, iomode); pnfs_layout_set_fail_bit(lo, iomode);
set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags);
if (lo->plh_return_iomode == 0) if (lo->plh_return_iomode == 0)
lo->plh_return_iomode = range.iomode; lo->plh_return_iomode = range.iomode;
else if (lo->plh_return_iomode != range.iomode) else if (lo->plh_return_iomode != range.iomode)
...@@ -2207,13 +2221,12 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) ...@@ -2207,13 +2221,12 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
if (ld->prepare_layoutcommit) { if (ld->prepare_layoutcommit) {
status = ld->prepare_layoutcommit(&data->args); status = ld->prepare_layoutcommit(&data->args);
if (status) { if (status) {
put_rpccred(data->cred);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags); set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags);
if (end_pos > nfsi->layout->plh_lwb) if (end_pos > nfsi->layout->plh_lwb)
nfsi->layout->plh_lwb = end_pos; nfsi->layout->plh_lwb = end_pos;
spin_unlock(&inode->i_lock); goto out_unlock;
put_rpccred(data->cred);
goto clear_layoutcommitting;
} }
} }
......
...@@ -1379,24 +1379,27 @@ static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr, ...@@ -1379,24 +1379,27 @@ static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
{ {
struct nfs_pgio_args *argp = &hdr->args; struct nfs_pgio_args *argp = &hdr->args;
struct nfs_pgio_res *resp = &hdr->res; struct nfs_pgio_res *resp = &hdr->res;
u64 size = argp->offset + resp->count;
if (!(fattr->valid & NFS_ATTR_FATTR_SIZE)) if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
fattr->size = size;
if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode)) {
fattr->valid &= ~NFS_ATTR_FATTR_SIZE;
return; return;
if (argp->offset + resp->count != fattr->size) }
return; if (size != fattr->size)
if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode))
return; return;
/* Set attribute barrier */ /* Set attribute barrier */
nfs_fattr_set_barrier(fattr); nfs_fattr_set_barrier(fattr);
/* ...and update size */
fattr->valid |= NFS_ATTR_FATTR_SIZE;
} }
void nfs_writeback_update_inode(struct nfs_pgio_header *hdr) void nfs_writeback_update_inode(struct nfs_pgio_header *hdr)
{ {
struct nfs_fattr *fattr = hdr->res.fattr; struct nfs_fattr *fattr = &hdr->fattr;
struct inode *inode = hdr->inode; struct inode *inode = hdr->inode;
if (fattr == NULL)
return;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
nfs_writeback_check_extend(hdr, fattr); nfs_writeback_check_extend(hdr, fattr);
nfs_post_op_update_inode_force_wcc_locked(inode, fattr); nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
......
...@@ -292,9 +292,12 @@ static inline void nfs_mark_for_revalidate(struct inode *inode) ...@@ -292,9 +292,12 @@ static inline void nfs_mark_for_revalidate(struct inode *inode)
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS; nfsi->cache_validity |= NFS_INO_INVALID_ATTR |
NFS_INO_REVAL_PAGECACHE |
NFS_INO_INVALID_ACCESS |
NFS_INO_INVALID_ACL;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; nfsi->cache_validity |= NFS_INO_INVALID_DATA;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
......
...@@ -220,7 +220,7 @@ struct nfs_server { ...@@ -220,7 +220,7 @@ struct nfs_server {
#define NFS_CAP_SYMLINKS (1U << 2) #define NFS_CAP_SYMLINKS (1U << 2)
#define NFS_CAP_ACLS (1U << 3) #define NFS_CAP_ACLS (1U << 3)
#define NFS_CAP_ATOMIC_OPEN (1U << 4) #define NFS_CAP_ATOMIC_OPEN (1U << 4)
#define NFS_CAP_CHANGE_ATTR (1U << 5) /* #define NFS_CAP_CHANGE_ATTR (1U << 5) */
#define NFS_CAP_FILEID (1U << 6) #define NFS_CAP_FILEID (1U << 6)
#define NFS_CAP_MODE (1U << 7) #define NFS_CAP_MODE (1U << 7)
#define NFS_CAP_NLINK (1U << 8) #define NFS_CAP_NLINK (1U << 8)
......
...@@ -240,8 +240,8 @@ static struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt, __be32 xid) ...@@ -240,8 +240,8 @@ static struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt, __be32 xid)
req = xprt_alloc_bc_req(xprt, GFP_ATOMIC); req = xprt_alloc_bc_req(xprt, GFP_ATOMIC);
if (!req) if (!req)
goto not_found; goto not_found;
/* Note: this 'free' request adds it to xprt->bc_pa_list */ list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list);
xprt_free_bc_request(req); xprt->bc_alloc_count++;
} }
req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst, req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
rq_bc_pa_list); rq_bc_pa_list);
...@@ -336,7 +336,7 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied) ...@@ -336,7 +336,7 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
spin_lock(&xprt->bc_pa_lock); spin_lock(&xprt->bc_pa_lock);
list_del(&req->rq_bc_pa_list); list_del(&req->rq_bc_pa_list);
xprt->bc_alloc_count--; xprt_dec_alloc_count(xprt, 1);
spin_unlock(&xprt->bc_pa_lock); spin_unlock(&xprt->bc_pa_lock);
req->rq_private_buf.len = copied; req->rq_private_buf.len = copied;
......
...@@ -1902,6 +1902,7 @@ call_transmit_status(struct rpc_task *task) ...@@ -1902,6 +1902,7 @@ call_transmit_status(struct rpc_task *task)
switch (task->tk_status) { switch (task->tk_status) {
case -EAGAIN: case -EAGAIN:
case -ENOBUFS:
break; break;
default: default:
dprint_status(task); dprint_status(task);
...@@ -1928,7 +1929,6 @@ call_transmit_status(struct rpc_task *task) ...@@ -1928,7 +1929,6 @@ call_transmit_status(struct rpc_task *task)
case -ECONNABORTED: case -ECONNABORTED:
case -EADDRINUSE: case -EADDRINUSE:
case -ENOTCONN: case -ENOTCONN:
case -ENOBUFS:
case -EPIPE: case -EPIPE:
rpc_task_force_reencode(task); rpc_task_force_reencode(task);
} }
...@@ -2057,12 +2057,13 @@ call_status(struct rpc_task *task) ...@@ -2057,12 +2057,13 @@ call_status(struct rpc_task *task)
case -ECONNABORTED: case -ECONNABORTED:
rpc_force_rebind(clnt); rpc_force_rebind(clnt);
case -EADDRINUSE: case -EADDRINUSE:
case -ENOBUFS:
rpc_delay(task, 3*HZ); rpc_delay(task, 3*HZ);
case -EPIPE: case -EPIPE:
case -ENOTCONN: case -ENOTCONN:
task->tk_action = call_bind; task->tk_action = call_bind;
break; break;
case -ENOBUFS:
rpc_delay(task, HZ>>2);
case -EAGAIN: case -EAGAIN:
task->tk_action = call_transmit; task->tk_action = call_transmit;
break; break;
......
...@@ -527,6 +527,10 @@ static int xs_local_send_request(struct rpc_task *task) ...@@ -527,6 +527,10 @@ static int xs_local_send_request(struct rpc_task *task)
true, &sent); true, &sent);
dprintk("RPC: %s(%u) = %d\n", dprintk("RPC: %s(%u) = %d\n",
__func__, xdr->len - req->rq_bytes_sent, status); __func__, xdr->len - req->rq_bytes_sent, status);
if (status == -EAGAIN && sock_writeable(transport->inet))
status = -ENOBUFS;
if (likely(sent > 0) || status == 0) { if (likely(sent > 0) || status == 0) {
req->rq_bytes_sent += sent; req->rq_bytes_sent += sent;
req->rq_xmit_bytes_sent += sent; req->rq_xmit_bytes_sent += sent;
...@@ -539,6 +543,7 @@ static int xs_local_send_request(struct rpc_task *task) ...@@ -539,6 +543,7 @@ static int xs_local_send_request(struct rpc_task *task)
switch (status) { switch (status) {
case -ENOBUFS: case -ENOBUFS:
break;
case -EAGAIN: case -EAGAIN:
status = xs_nospace(task); status = xs_nospace(task);
break; break;
...@@ -589,6 +594,9 @@ static int xs_udp_send_request(struct rpc_task *task) ...@@ -589,6 +594,9 @@ static int xs_udp_send_request(struct rpc_task *task)
if (status == -EPERM) if (status == -EPERM)
goto process_status; goto process_status;
if (status == -EAGAIN && sock_writeable(transport->inet))
status = -ENOBUFS;
if (sent > 0 || status == 0) { if (sent > 0 || status == 0) {
req->rq_xmit_bytes_sent += sent; req->rq_xmit_bytes_sent += sent;
if (sent >= req->rq_slen) if (sent >= req->rq_slen)
...@@ -669,9 +677,6 @@ static int xs_tcp_send_request(struct rpc_task *task) ...@@ -669,9 +677,6 @@ static int xs_tcp_send_request(struct rpc_task *task)
dprintk("RPC: xs_tcp_send_request(%u) = %d\n", dprintk("RPC: xs_tcp_send_request(%u) = %d\n",
xdr->len - req->rq_bytes_sent, status); xdr->len - req->rq_bytes_sent, status);
if (unlikely(sent == 0 && status < 0))
break;
/* If we've sent the entire packet, immediately /* If we've sent the entire packet, immediately
* reset the count of bytes sent. */ * reset the count of bytes sent. */
req->rq_bytes_sent += sent; req->rq_bytes_sent += sent;
...@@ -681,18 +686,21 @@ static int xs_tcp_send_request(struct rpc_task *task) ...@@ -681,18 +686,21 @@ static int xs_tcp_send_request(struct rpc_task *task)
return 0; return 0;
} }
if (sent != 0) if (status < 0)
continue; break;
status = -EAGAIN; if (sent == 0) {
break; status = -EAGAIN;
break;
}
} }
if (status == -EAGAIN && sk_stream_is_writeable(transport->inet))
status = -ENOBUFS;
switch (status) { switch (status) {
case -ENOTSOCK: case -ENOTSOCK:
status = -ENOTCONN; status = -ENOTCONN;
/* Should we call xs_close() here? */ /* Should we call xs_close() here? */
break; break;
case -ENOBUFS:
case -EAGAIN: case -EAGAIN:
status = xs_nospace(task); status = xs_nospace(task);
break; break;
...@@ -703,6 +711,7 @@ static int xs_tcp_send_request(struct rpc_task *task) ...@@ -703,6 +711,7 @@ static int xs_tcp_send_request(struct rpc_task *task)
case -ECONNREFUSED: case -ECONNREFUSED:
case -ENOTCONN: case -ENOTCONN:
case -EADDRINUSE: case -EADDRINUSE:
case -ENOBUFS:
case -EPIPE: case -EPIPE:
clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment