Commit daaadd22 authored by Trond Myklebust's avatar Trond Myklebust

Merge branch 'bugfixes'

* bugfixes:
  SUNRPC: Fixup socket wait for memory
  SUNRPC: Fix a missing break in rpc_anyaddr()
  pNFS/flexfiles: Fix an Oopsable typo in ff_mirror_match_fh()
  NFS: Fix attribute cache revalidation
  NFS: Ensure we revalidate attributes before using execute_ok()
  NFS: Flush reclaim writes using FLUSH_COND_STABLE
  NFS: Background flush should not be low priority
  NFSv4.1/pnfs: Fixup an lo->plh_block_lgets imbalance in layoutreturn
  NFSv4: Don't perform cached access checks before we've OPENed the file
  NFS: Allow the combination pNFS and labeled NFS
  NFS42: handle layoutstats stateid error
  nfs: Fix race in __update_open_stateid()
  nfs: fix missing assignment in nfs4_sequence_done tracepoint
parents 210c7c17 13331a55
...@@ -2432,6 +2432,20 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) ...@@ -2432,6 +2432,20 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
} }
EXPORT_SYMBOL_GPL(nfs_may_open); 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;
if (mask & MAY_NOT_BLOCK)
ret = nfs_revalidate_inode_rcu(server, inode);
else
ret = nfs_revalidate_inode(server, inode);
if (ret == 0 && !execute_ok(inode))
ret = -EACCES;
return ret;
}
int nfs_permission(struct inode *inode, int mask) int nfs_permission(struct inode *inode, int mask)
{ {
struct rpc_cred *cred; struct rpc_cred *cred;
...@@ -2449,6 +2463,9 @@ int nfs_permission(struct inode *inode, int mask) ...@@ -2449,6 +2463,9 @@ int nfs_permission(struct inode *inode, int mask)
case S_IFLNK: case S_IFLNK:
goto out; goto out;
case S_IFREG: case S_IFREG:
if ((mask & MAY_OPEN) &&
nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN))
return 0;
break; break;
case S_IFDIR: case S_IFDIR:
/* /*
...@@ -2481,8 +2498,8 @@ int nfs_permission(struct inode *inode, int mask) ...@@ -2481,8 +2498,8 @@ int nfs_permission(struct inode *inode, int mask)
res = PTR_ERR(cred); res = PTR_ERR(cred);
} }
out: out:
if (!res && (mask & MAY_EXEC) && !execute_ok(inode)) if (!res && (mask & MAY_EXEC))
res = -EACCES; res = nfs_execute_ok(inode, mask);
dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n", dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n",
inode->i_sb->s_id, inode->i_ino, mask, res); inode->i_sb->s_id, inode->i_ino, mask, res);
......
...@@ -145,7 +145,7 @@ static bool ff_mirror_match_fh(const struct nfs4_ff_layout_mirror *m1, ...@@ -145,7 +145,7 @@ static bool ff_mirror_match_fh(const struct nfs4_ff_layout_mirror *m1,
return false; return false;
for (i = 0; i < m1->fh_versions_cnt; i++) { for (i = 0; i < m1->fh_versions_cnt; i++) {
bool found_fh = false; bool found_fh = false;
for (j = 0; j < m2->fh_versions_cnt; i++) { for (j = 0; j < m2->fh_versions_cnt; j++) {
if (nfs_compare_fh(&m1->fh_versions[i], if (nfs_compare_fh(&m1->fh_versions[i],
&m2->fh_versions[j]) == 0) { &m2->fh_versions[j]) == 0) {
found_fh = true; found_fh = true;
......
...@@ -1653,6 +1653,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1653,6 +1653,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
unsigned long invalid = 0; unsigned long invalid = 0;
unsigned long now = jiffies; unsigned long now = jiffies;
unsigned long save_cache_validity; unsigned long save_cache_validity;
bool cache_revalidated = true;
dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n", dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
__func__, inode->i_sb->s_id, inode->i_ino, __func__, inode->i_sb->s_id, inode->i_ino,
...@@ -1714,22 +1715,28 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1714,22 +1715,28 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfs_force_lookup_revalidate(inode); nfs_force_lookup_revalidate(inode);
inode->i_version = fattr->change_attr; inode->i_version = fattr->change_attr;
} }
} else } else {
nfsi->cache_validity |= save_cache_validity; nfsi->cache_validity |= save_cache_validity;
cache_revalidated = false;
}
if (fattr->valid & NFS_ATTR_FATTR_MTIME) { if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
} else if (server->caps & NFS_CAP_MTIME) } else if (server->caps & NFS_CAP_MTIME) {
nfsi->cache_validity |= save_cache_validity & nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR (NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
cache_revalidated = false;
}
if (fattr->valid & NFS_ATTR_FATTR_CTIME) { if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
} else if (server->caps & NFS_CAP_CTIME) } else if (server->caps & NFS_CAP_CTIME) {
nfsi->cache_validity |= save_cache_validity & nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR (NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
cache_revalidated = false;
}
/* Check if our cached file size is stale */ /* Check if our cached file size is stale */
if (fattr->valid & NFS_ATTR_FATTR_SIZE) { if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
...@@ -1749,19 +1756,23 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1749,19 +1756,23 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
(long long)cur_isize, (long long)cur_isize,
(long long)new_isize); (long long)new_isize);
} }
} else } else {
nfsi->cache_validity |= save_cache_validity & nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR (NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_PAGECACHE
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
cache_revalidated = false;
}
if (fattr->valid & NFS_ATTR_FATTR_ATIME) if (fattr->valid & NFS_ATTR_FATTR_ATIME)
memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
else if (server->caps & NFS_CAP_ATIME) else if (server->caps & NFS_CAP_ATIME) {
nfsi->cache_validity |= save_cache_validity & nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATIME (NFS_INO_INVALID_ATIME
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
cache_revalidated = false;
}
if (fattr->valid & NFS_ATTR_FATTR_MODE) { if (fattr->valid & NFS_ATTR_FATTR_MODE) {
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
...@@ -1770,36 +1781,42 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1770,36 +1781,42 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_mode = newmode; inode->i_mode = newmode;
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
} }
} else if (server->caps & NFS_CAP_MODE) } else if (server->caps & NFS_CAP_MODE) {
nfsi->cache_validity |= save_cache_validity & nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR (NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL | NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
cache_revalidated = false;
}
if (fattr->valid & NFS_ATTR_FATTR_OWNER) { if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
if (!uid_eq(inode->i_uid, fattr->uid)) { if (!uid_eq(inode->i_uid, fattr->uid)) {
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
inode->i_uid = fattr->uid; inode->i_uid = fattr->uid;
} }
} else if (server->caps & NFS_CAP_OWNER) } else if (server->caps & NFS_CAP_OWNER) {
nfsi->cache_validity |= save_cache_validity & nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR (NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL | NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
cache_revalidated = false;
}
if (fattr->valid & NFS_ATTR_FATTR_GROUP) { if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
if (!gid_eq(inode->i_gid, fattr->gid)) { if (!gid_eq(inode->i_gid, fattr->gid)) {
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
inode->i_gid = fattr->gid; inode->i_gid = fattr->gid;
} }
} else if (server->caps & NFS_CAP_OWNER_GROUP) } else if (server->caps & NFS_CAP_OWNER_GROUP) {
nfsi->cache_validity |= save_cache_validity & nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR (NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL | NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
cache_revalidated = false;
}
if (fattr->valid & NFS_ATTR_FATTR_NLINK) { if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
if (inode->i_nlink != fattr->nlink) { if (inode->i_nlink != fattr->nlink) {
...@@ -1808,19 +1825,22 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1808,19 +1825,22 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
invalid |= NFS_INO_INVALID_DATA; invalid |= NFS_INO_INVALID_DATA;
set_nlink(inode, fattr->nlink); set_nlink(inode, fattr->nlink);
} }
} else if (server->caps & NFS_CAP_NLINK) } else if (server->caps & NFS_CAP_NLINK) {
nfsi->cache_validity |= save_cache_validity & nfsi->cache_validity |= save_cache_validity &
(NFS_INO_INVALID_ATTR (NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_FORCED); | NFS_INO_REVAL_FORCED);
cache_revalidated = false;
}
if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
/* /*
* report the blocks in 512byte units * report the blocks in 512byte units
*/ */
inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
} } else if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
inode->i_blocks = fattr->du.nfs2.blocks; inode->i_blocks = fattr->du.nfs2.blocks;
else
cache_revalidated = false;
/* Update attrtimeo value if we're out of the unstable period */ /* Update attrtimeo value if we're out of the unstable period */
if (invalid & NFS_INO_INVALID_ATTR) { if (invalid & NFS_INO_INVALID_ATTR) {
...@@ -1830,9 +1850,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1830,9 +1850,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
/* Set barrier to be more recent than all outstanding updates */ /* Set barrier to be more recent than all outstanding updates */
nfsi->attr_gencount = nfs_inc_attr_generation_counter(); nfsi->attr_gencount = nfs_inc_attr_generation_counter();
} else { } else {
if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { if (cache_revalidated) {
if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) if (!time_in_range_open(now, nfsi->attrtimeo_timestamp,
nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
nfsi->attrtimeo <<= 1;
if (nfsi->attrtimeo > NFS_MAXATTRTIMEO(inode))
nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
}
nfsi->attrtimeo_timestamp = now; nfsi->attrtimeo_timestamp = now;
} }
/* Set the barrier to be more recent than this fattr */ /* Set the barrier to be more recent than this fattr */
...@@ -1841,7 +1865,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1841,7 +1865,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
} }
/* Don't declare attrcache up to date if there were no attrs! */ /* Don't declare attrcache up to date if there were no attrs! */
if (fattr->valid != 0) if (cache_revalidated)
invalid &= ~NFS_INO_INVALID_ATTR; invalid &= ~NFS_INO_INVALID_ATTR;
/* Don't invalidate the data if we were to blame */ /* Don't invalidate the data if we were to blame */
......
...@@ -204,6 +204,8 @@ static void ...@@ -204,6 +204,8 @@ static void
nfs42_layoutstat_done(struct rpc_task *task, void *calldata) nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
{ {
struct nfs42_layoutstat_data *data = calldata; struct nfs42_layoutstat_data *data = calldata;
struct inode *inode = data->inode;
struct pnfs_layout_hdr *lo;
if (!nfs4_sequence_done(task, &data->res.seq_res)) if (!nfs4_sequence_done(task, &data->res.seq_res))
return; return;
...@@ -211,12 +213,35 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata) ...@@ -211,12 +213,35 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
switch (task->tk_status) { switch (task->tk_status) {
case 0: case 0:
break; break;
case -NFS4ERR_EXPIRED:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_OLD_STATEID:
case -NFS4ERR_BAD_STATEID:
spin_lock(&inode->i_lock);
lo = NFS_I(inode)->layout;
if (lo && nfs4_stateid_match(&data->args.stateid,
&lo->plh_stateid)) {
LIST_HEAD(head);
/*
* Mark the bad layout state as invalid, then retry
* with the current stateid.
*/
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
pnfs_mark_matching_lsegs_invalid(lo, &head, NULL);
spin_unlock(&inode->i_lock);
pnfs_free_lseg_list(&head);
} else
spin_unlock(&inode->i_lock);
break;
case -ENOTSUPP: case -ENOTSUPP:
case -EOPNOTSUPP: case -EOPNOTSUPP:
NFS_SERVER(data->inode)->caps &= ~NFS_CAP_LAYOUTSTATS; NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
default: default:
dprintk("%s server returns %d\n", __func__, task->tk_status); break;
} }
dprintk("%s server returns %d\n", __func__, task->tk_status);
} }
static void static void
......
...@@ -208,6 +208,9 @@ static const u32 nfs4_pnfs_open_bitmap[3] = { ...@@ -208,6 +208,9 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
| FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_METADATA
| FATTR4_WORD1_TIME_MODIFY, | FATTR4_WORD1_TIME_MODIFY,
FATTR4_WORD2_MDSTHRESHOLD FATTR4_WORD2_MDSTHRESHOLD
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
| FATTR4_WORD2_SECURITY_LABEL
#endif
}; };
static const u32 nfs4_open_noattr_bitmap[3] = { static const u32 nfs4_open_noattr_bitmap[3] = {
...@@ -1385,6 +1388,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s ...@@ -1385,6 +1388,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
* Protect the call to nfs4_state_set_mode_locked and * Protect the call to nfs4_state_set_mode_locked and
* serialise the stateid update * serialise the stateid update
*/ */
spin_lock(&state->owner->so_lock);
write_seqlock(&state->seqlock); write_seqlock(&state->seqlock);
if (deleg_stateid != NULL) { if (deleg_stateid != NULL) {
nfs4_stateid_copy(&state->stateid, deleg_stateid); nfs4_stateid_copy(&state->stateid, deleg_stateid);
...@@ -1393,7 +1397,6 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s ...@@ -1393,7 +1397,6 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
if (open_stateid != NULL) if (open_stateid != NULL)
nfs_set_open_stateid_locked(state, open_stateid, fmode); nfs_set_open_stateid_locked(state, open_stateid, fmode);
write_sequnlock(&state->seqlock); write_sequnlock(&state->seqlock);
spin_lock(&state->owner->so_lock);
update_open_stateflags(state, fmode); update_open_stateflags(state, fmode);
spin_unlock(&state->owner->so_lock); spin_unlock(&state->owner->so_lock);
} }
...@@ -8079,7 +8082,6 @@ static void nfs4_layoutreturn_release(void *calldata) ...@@ -8079,7 +8082,6 @@ static void nfs4_layoutreturn_release(void *calldata)
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_clear_layoutreturn_waitbit(lo); pnfs_clear_layoutreturn_waitbit(lo);
lo->plh_block_lgets--;
spin_unlock(&lo->plh_inode->i_lock); spin_unlock(&lo->plh_inode->i_lock);
pnfs_free_lseg_list(&freeme); pnfs_free_lseg_list(&freeme);
pnfs_put_layout_hdr(lrp->args.layout); pnfs_put_layout_hdr(lrp->args.layout);
......
...@@ -321,6 +321,7 @@ TRACE_EVENT(nfs4_sequence_done, ...@@ -321,6 +321,7 @@ TRACE_EVENT(nfs4_sequence_done,
__entry->highest_slotid = res->sr_highest_slotid; __entry->highest_slotid = res->sr_highest_slotid;
__entry->target_highest_slotid = __entry->target_highest_slotid =
res->sr_target_highest_slotid; res->sr_target_highest_slotid;
__entry->status_flags = res->sr_status_flags;
__entry->error = res->sr_status; __entry->error = res->sr_status;
), ),
TP_printk( TP_printk(
......
...@@ -246,11 +246,9 @@ static int wb_priority(struct writeback_control *wbc) ...@@ -246,11 +246,9 @@ static int wb_priority(struct writeback_control *wbc)
{ {
int ret = 0; int ret = 0;
if (wbc->for_reclaim) if (wbc->for_reclaim)
return FLUSH_HIGHPRI | FLUSH_STABLE; return FLUSH_HIGHPRI | FLUSH_COND_STABLE;
if (wbc->sync_mode == WB_SYNC_ALL) if (wbc->sync_mode == WB_SYNC_ALL)
ret = FLUSH_COND_STABLE; ret = FLUSH_COND_STABLE;
if (wbc->for_kupdate || wbc->for_background)
ret |= FLUSH_LOWPRI;
return ret; return ret;
} }
......
...@@ -1217,6 +1217,7 @@ static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen) ...@@ -1217,6 +1217,7 @@ static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen)
return -EINVAL; return -EINVAL;
memcpy(buf, &rpc_in6addr_loopback, memcpy(buf, &rpc_in6addr_loopback,
sizeof(rpc_in6addr_loopback)); sizeof(rpc_in6addr_loopback));
break;
default: default:
dprintk("RPC: %s: address family not supported\n", dprintk("RPC: %s: address family not supported\n",
__func__); __func__);
......
...@@ -398,7 +398,6 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, ...@@ -398,7 +398,6 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
if (unlikely(!sock)) if (unlikely(!sock))
return -ENOTSOCK; return -ENOTSOCK;
clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags);
if (base != 0) { if (base != 0) {
addr = NULL; addr = NULL;
addrlen = 0; addrlen = 0;
...@@ -442,7 +441,6 @@ static void xs_nospace_callback(struct rpc_task *task) ...@@ -442,7 +441,6 @@ static void xs_nospace_callback(struct rpc_task *task)
struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt); struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
transport->inet->sk_write_pending--; transport->inet->sk_write_pending--;
clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
} }
/** /**
...@@ -467,20 +465,11 @@ static int xs_nospace(struct rpc_task *task) ...@@ -467,20 +465,11 @@ static int xs_nospace(struct rpc_task *task)
/* Don't race with disconnect */ /* Don't race with disconnect */
if (xprt_connected(xprt)) { if (xprt_connected(xprt)) {
if (test_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags)) { /* wait for more buffer space */
/* sk->sk_write_pending++;
* Notify TCP that we're limited by the application xprt_wait_for_buffer_space(task, xs_nospace_callback);
* window size } else
*/
set_bit(SOCK_NOSPACE, &transport->sock->flags);
sk->sk_write_pending++;
/* ...and wait for more buffer space */
xprt_wait_for_buffer_space(task, xs_nospace_callback);
}
} else {
clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
ret = -ENOTCONN; ret = -ENOTCONN;
}
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
...@@ -616,9 +605,6 @@ static int xs_udp_send_request(struct rpc_task *task) ...@@ -616,9 +605,6 @@ static int xs_udp_send_request(struct rpc_task *task)
case -EAGAIN: case -EAGAIN:
status = xs_nospace(task); status = xs_nospace(task);
break; break;
default:
dprintk("RPC: sendmsg returned unrecognized error %d\n",
-status);
case -ENETUNREACH: case -ENETUNREACH:
case -ENOBUFS: case -ENOBUFS:
case -EPIPE: case -EPIPE:
...@@ -626,7 +612,10 @@ static int xs_udp_send_request(struct rpc_task *task) ...@@ -626,7 +612,10 @@ static int xs_udp_send_request(struct rpc_task *task)
case -EPERM: case -EPERM:
/* When the server has died, an ICMP port unreachable message /* When the server has died, an ICMP port unreachable message
* prompts ECONNREFUSED. */ * prompts ECONNREFUSED. */
clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags); break;
default:
dprintk("RPC: sendmsg returned unrecognized error %d\n",
-status);
} }
return status; return status;
...@@ -706,16 +695,16 @@ static int xs_tcp_send_request(struct rpc_task *task) ...@@ -706,16 +695,16 @@ static int xs_tcp_send_request(struct rpc_task *task)
case -EAGAIN: case -EAGAIN:
status = xs_nospace(task); status = xs_nospace(task);
break; break;
default:
dprintk("RPC: sendmsg returned unrecognized error %d\n",
-status);
case -ECONNRESET: case -ECONNRESET:
case -ECONNREFUSED: case -ECONNREFUSED:
case -ENOTCONN: case -ENOTCONN:
case -EADDRINUSE: case -EADDRINUSE:
case -ENOBUFS: case -ENOBUFS:
case -EPIPE: case -EPIPE:
clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags); break;
default:
dprintk("RPC: sendmsg returned unrecognized error %d\n",
-status);
} }
return status; return status;
...@@ -1609,19 +1598,23 @@ static void xs_tcp_state_change(struct sock *sk) ...@@ -1609,19 +1598,23 @@ static void xs_tcp_state_change(struct sock *sk)
static void xs_write_space(struct sock *sk) static void xs_write_space(struct sock *sk)
{ {
struct socket *sock; struct socket_wq *wq;
struct rpc_xprt *xprt; struct rpc_xprt *xprt;
if (unlikely(!(sock = sk->sk_socket))) if (!sk->sk_socket)
return; return;
clear_bit(SOCK_NOSPACE, &sock->flags); clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
if (unlikely(!(xprt = xprt_from_sock(sk)))) if (unlikely(!(xprt = xprt_from_sock(sk))))
return; return;
if (test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags) == 0) rcu_read_lock();
return; wq = rcu_dereference(sk->sk_wq);
if (!wq || test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags) == 0)
goto out;
xprt_write_space(xprt); xprt_write_space(xprt);
out:
rcu_read_unlock();
} }
/** /**
......
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