Commit f1823acf authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6

* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
  NFS: Fix the fix to Bugzilla #11061, when IPv6 isn't defined...
  SUNRPC: xprt_connect() don't abort the task if the transport isn't bound
  SUNRPC: Fix an Oops due to socket not set up yet...
  Bug 11061, NFS mounts dropped
  NFS: Handle -ESTALE error in access()
  NLM: Fix GRANT callback address comparison when IPv6 is enabled
  NLM: Shrink the IPv4-only version of nlm_cmp_addr()
  NFSv3: Fix posix ACL code
  NFS: Fix misparsing of nfsv4 fs_locations attribute (take 2)
  SUNRPC: Tighten up the task locking rules in __rpc_execute()
parents ff9cb43c 9f4c899c
...@@ -139,6 +139,55 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) ...@@ -139,6 +139,55 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
return 0; return 0;
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static const struct in6_addr *nlmclnt_map_v4addr(const struct sockaddr *sap,
struct in6_addr *addr_mapped)
{
const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
switch (sap->sa_family) {
case AF_INET6:
return &((const struct sockaddr_in6 *)sap)->sin6_addr;
case AF_INET:
ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, addr_mapped);
return addr_mapped;
}
return NULL;
}
/*
* If lockd is using a PF_INET6 listener, all incoming requests appear
* to come from AF_INET6 remotes. The address of AF_INET remotes are
* mapped to AF_INET6 automatically by the network layer. In case the
* user passed an AF_INET server address at mount time, ensure both
* addresses are AF_INET6 before comparing them.
*/
static int nlmclnt_cmp_addr(const struct nlm_host *host,
const struct sockaddr *sap)
{
const struct in6_addr *addr1;
const struct in6_addr *addr2;
struct in6_addr addr1_mapped;
struct in6_addr addr2_mapped;
addr1 = nlmclnt_map_v4addr(nlm_addr(host), &addr1_mapped);
if (likely(addr1 != NULL)) {
addr2 = nlmclnt_map_v4addr(sap, &addr2_mapped);
if (likely(addr2 != NULL))
return ipv6_addr_equal(addr1, addr2);
}
return 0;
}
#else /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
static int nlmclnt_cmp_addr(const struct nlm_host *host,
const struct sockaddr *sap)
{
return nlm_cmp_addr(nlm_addr(host), sap);
}
#endif /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
/* /*
* The server lockd has called us back to tell us the lock was granted * The server lockd has called us back to tell us the lock was granted
*/ */
...@@ -166,7 +215,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock) ...@@ -166,7 +215,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
*/ */
if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid) if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
continue; continue;
if (!nlm_cmp_addr(nlm_addr(block->b_host), addr)) if (!nlmclnt_cmp_addr(block->b_host, addr))
continue; continue;
if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0) if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
continue; continue;
......
...@@ -255,6 +255,32 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, ...@@ -255,6 +255,32 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
} }
return 0; return 0;
} }
/*
* Test if two ip6 socket addresses refer to the same socket by
* comparing relevant fields. The padding bytes specifically, are not
* compared. sin6_flowinfo is not compared because it only affects QoS
* and sin6_scope_id is only compared if the address is "link local"
* because "link local" addresses need only be unique to a specific
* link. Conversely, ordinary unicast addresses might have different
* sin6_scope_id.
*
* The caller should ensure both socket addresses are AF_INET6.
*/
static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
const struct sockaddr_in6 *saddr1 = (const struct sockaddr_in6 *)sa1;
const struct sockaddr_in6 *saddr2 = (const struct sockaddr_in6 *)sa2;
if (!ipv6_addr_equal(&saddr1->sin6_addr,
&saddr1->sin6_addr))
return 0;
if (ipv6_addr_scope(&saddr1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
saddr1->sin6_scope_id != saddr2->sin6_scope_id)
return 0;
return saddr1->sin6_port == saddr2->sin6_port;
}
#else #else
static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
const struct sockaddr_in *sa2) const struct sockaddr_in *sa2)
...@@ -270,8 +296,51 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, ...@@ -270,8 +296,51 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
(const struct sockaddr_in *)sa2); (const struct sockaddr_in *)sa2);
} }
static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1,
const struct sockaddr * sa2)
{
return 0;
}
#endif #endif
/*
* Test if two ip4 socket addresses refer to the same socket, by
* comparing relevant fields. The padding bytes specifically, are
* not compared.
*
* The caller should ensure both socket addresses are AF_INET.
*/
static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
const struct sockaddr_in *saddr1 = (const struct sockaddr_in *)sa1;
const struct sockaddr_in *saddr2 = (const struct sockaddr_in *)sa2;
if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr)
return 0;
return saddr1->sin_port == saddr2->sin_port;
}
/*
* Test if two socket addresses represent the same actual socket,
* by comparing (only) relevant fields.
*/
static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
if (sa1->sa_family != sa2->sa_family)
return 0;
switch (sa1->sa_family) {
case AF_INET:
return nfs_sockaddr_cmp_ip4(sa1, sa2);
case AF_INET6:
return nfs_sockaddr_cmp_ip6(sa1, sa2);
}
return 0;
}
/* /*
* Find a client by IP address and protocol version * Find a client by IP address and protocol version
* - returns NULL if no such client * - returns NULL if no such client
...@@ -344,8 +413,10 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp) ...@@ -344,8 +413,10 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data) static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data)
{ {
struct nfs_client *clp; struct nfs_client *clp;
const struct sockaddr *sap = data->addr;
list_for_each_entry(clp, &nfs_client_list, cl_share_link) { list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
/* Don't match clients that failed to initialise properly */ /* Don't match clients that failed to initialise properly */
if (clp->cl_cons_state < 0) if (clp->cl_cons_state < 0)
continue; continue;
...@@ -358,7 +429,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat ...@@ -358,7 +429,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
continue; continue;
/* Match the full socket address */ /* Match the full socket address */
if (memcmp(&clp->cl_addr, data->addr, sizeof(clp->cl_addr)) != 0) if (!nfs_sockaddr_cmp(sap, clap))
continue; continue;
atomic_inc(&clp->cl_count); atomic_inc(&clp->cl_count);
......
...@@ -1892,8 +1892,14 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) ...@@ -1892,8 +1892,14 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
cache.cred = cred; cache.cred = cred;
cache.jiffies = jiffies; cache.jiffies = jiffies;
status = NFS_PROTO(inode)->access(inode, &cache); status = NFS_PROTO(inode)->access(inode, &cache);
if (status != 0) if (status != 0) {
if (status == -ESTALE) {
nfs_zap_caches(inode);
if (!S_ISDIR(inode->i_mode))
set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
}
return status; return status;
}
nfs_access_add_cache(inode, &cache); nfs_access_add_cache(inode, &cache);
out: out:
if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
......
...@@ -292,7 +292,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, ...@@ -292,7 +292,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct nfs_fattr fattr; struct nfs_fattr fattr;
struct page *pages[NFSACL_MAXPAGES] = { }; struct page *pages[NFSACL_MAXPAGES];
struct nfs3_setaclargs args = { struct nfs3_setaclargs args = {
.inode = inode, .inode = inode,
.mask = NFS_ACL, .mask = NFS_ACL,
...@@ -303,7 +303,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, ...@@ -303,7 +303,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
.rpc_argp = &args, .rpc_argp = &args,
.rpc_resp = &fattr, .rpc_resp = &fattr,
}; };
int status, count; int status;
status = -EOPNOTSUPP; status = -EOPNOTSUPP;
if (!nfs_server_capable(inode, NFS_CAP_ACLS)) if (!nfs_server_capable(inode, NFS_CAP_ACLS))
...@@ -319,6 +319,20 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, ...@@ -319,6 +319,20 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
args.mask |= NFS_DFACL; args.mask |= NFS_DFACL;
args.acl_default = dfacl; args.acl_default = dfacl;
args.len = nfsacl_size(acl, dfacl);
} else
args.len = nfsacl_size(acl, NULL);
if (args.len > NFS_ACL_INLINE_BUFSIZE) {
unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT);
status = -ENOMEM;
do {
args.pages[args.npages] = alloc_page(GFP_KERNEL);
if (args.pages[args.npages] == NULL)
goto out_freepages;
args.npages++;
} while (args.npages < npages);
} }
dprintk("NFS call setacl\n"); dprintk("NFS call setacl\n");
...@@ -329,10 +343,6 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, ...@@ -329,10 +343,6 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
nfs_zap_acl_cache(inode); nfs_zap_acl_cache(inode);
dprintk("NFS reply setacl: %d\n", status); dprintk("NFS reply setacl: %d\n", status);
/* pages may have been allocated at the xdr layer. */
for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
__free_page(args.pages[count]);
switch (status) { switch (status) {
case 0: case 0:
status = nfs_refresh_inode(inode, &fattr); status = nfs_refresh_inode(inode, &fattr);
...@@ -346,6 +356,11 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, ...@@ -346,6 +356,11 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
case -ENOTSUPP: case -ENOTSUPP:
status = -EOPNOTSUPP; status = -EOPNOTSUPP;
} }
out_freepages:
while (args.npages != 0) {
args.npages--;
__free_page(args.pages[args.npages]);
}
out: out:
return status; return status;
} }
......
...@@ -82,8 +82,10 @@ ...@@ -82,8 +82,10 @@
#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
#define ACL3_getaclargs_sz (NFS3_fh_sz+1) #define ACL3_getaclargs_sz (NFS3_fh_sz+1)
#define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3)) #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3)) XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
/* /*
...@@ -703,28 +705,18 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p, ...@@ -703,28 +705,18 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
struct nfs3_setaclargs *args) struct nfs3_setaclargs *args)
{ {
struct xdr_buf *buf = &req->rq_snd_buf; struct xdr_buf *buf = &req->rq_snd_buf;
unsigned int base, len_in_head, len = nfsacl_size( unsigned int base;
(args->mask & NFS_ACL) ? args->acl_access : NULL, int err;
(args->mask & NFS_DFACL) ? args->acl_default : NULL);
int count, err;
p = xdr_encode_fhandle(p, NFS_FH(args->inode)); p = xdr_encode_fhandle(p, NFS_FH(args->inode));
*p++ = htonl(args->mask); *p++ = htonl(args->mask);
base = (char *)p - (char *)buf->head->iov_base; req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
/* put as much of the acls into head as possible. */ base = req->rq_slen;
len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
len -= len_in_head; if (args->npages != 0)
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2)); xdr_encode_pages(buf, args->pages, 0, args->len);
else
for (count = 0; (count << PAGE_SHIFT) < len; count++) { req->rq_slen += args->len;
args->pages[count] = alloc_page(GFP_KERNEL);
if (!args->pages[count]) {
while (count)
__free_page(args->pages[--count]);
return -ENOMEM;
}
}
xdr_encode_pages(buf, args->pages, 0, len);
err = nfsacl_encode(buf, base, args->inode, err = nfsacl_encode(buf, base, args->inode,
(args->mask & NFS_ACL) ? (args->mask & NFS_ACL) ?
......
...@@ -21,7 +21,9 @@ ...@@ -21,7 +21,9 @@
#define NFSDBG_FACILITY NFSDBG_VFS #define NFSDBG_FACILITY NFSDBG_VFS
/* /*
* Check if fs_root is valid * Convert the NFSv4 pathname components into a standard posix path.
*
* Note that the resulting string will be placed at the end of the buffer
*/ */
static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname, static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
char *buffer, ssize_t buflen) char *buffer, ssize_t buflen)
...@@ -99,21 +101,20 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, ...@@ -99,21 +101,20 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
{ {
struct vfsmount *mnt = ERR_PTR(-ENOENT); struct vfsmount *mnt = ERR_PTR(-ENOENT);
char *mnt_path; char *mnt_path;
int page2len; unsigned int maxbuflen;
unsigned int s; unsigned int s;
mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
if (IS_ERR(mnt_path)) if (IS_ERR(mnt_path))
return mnt; return mnt;
mountdata->mnt_path = mnt_path; mountdata->mnt_path = mnt_path;
page2 += strlen(mnt_path) + 1; maxbuflen = mnt_path - 1 - page2;
page2len = PAGE_SIZE - strlen(mnt_path) - 1;
for (s = 0; s < location->nservers; s++) { for (s = 0; s < location->nservers; s++) {
const struct nfs4_string *buf = &location->servers[s]; const struct nfs4_string *buf = &location->servers[s];
struct sockaddr_storage addr; struct sockaddr_storage addr;
if (buf->len <= 0 || buf->len >= PAGE_SIZE) if (buf->len <= 0 || buf->len >= maxbuflen)
continue; continue;
mountdata->addr = (struct sockaddr *)&addr; mountdata->addr = (struct sockaddr *)&addr;
...@@ -126,8 +127,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, ...@@ -126,8 +127,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
continue; continue;
nfs_set_port(mountdata->addr, NFS_PORT); nfs_set_port(mountdata->addr, NFS_PORT);
strncpy(page2, buf->data, page2len); memcpy(page2, buf->data, buf->len);
page2[page2len] = '\0'; page2[buf->len] = '\0';
mountdata->hostname = page2; mountdata->hostname = page2;
snprintf(page, PAGE_SIZE, "%s:%s", snprintf(page, PAGE_SIZE, "%s:%s",
......
...@@ -346,6 +346,7 @@ static inline int __nlm_cmp_addr4(const struct sockaddr *sap1, ...@@ -346,6 +346,7 @@ static inline int __nlm_cmp_addr4(const struct sockaddr *sap1,
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static inline int __nlm_cmp_addr6(const struct sockaddr *sap1, static inline int __nlm_cmp_addr6(const struct sockaddr *sap1,
const struct sockaddr *sap2) const struct sockaddr *sap2)
{ {
...@@ -353,6 +354,13 @@ static inline int __nlm_cmp_addr6(const struct sockaddr *sap1, ...@@ -353,6 +354,13 @@ static inline int __nlm_cmp_addr6(const struct sockaddr *sap1,
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2; const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr); return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
} }
#else /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
static inline int __nlm_cmp_addr6(const struct sockaddr *sap1,
const struct sockaddr *sap2)
{
return 0;
}
#endif /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
/* /*
* Compare two host addresses * Compare two host addresses
......
...@@ -406,6 +406,8 @@ struct nfs3_setaclargs { ...@@ -406,6 +406,8 @@ struct nfs3_setaclargs {
int mask; int mask;
struct posix_acl * acl_access; struct posix_acl * acl_access;
struct posix_acl * acl_default; struct posix_acl * acl_default;
size_t len;
unsigned int npages;
struct page ** pages; struct page ** pages;
}; };
......
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
#define NFSACL_MAXPAGES ((2*(8+12*NFS_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \ #define NFSACL_MAXPAGES ((2*(8+12*NFS_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \
>> PAGE_SHIFT) >> PAGE_SHIFT)
#define NFS_ACL_MAX_ENTRIES_INLINE (5)
#define NFS_ACL_INLINE_BUFSIZE ((2*(2+3*NFS_ACL_MAX_ENTRIES_INLINE)) << 2)
static inline unsigned int static inline unsigned int
nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default) nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
{ {
......
...@@ -293,11 +293,6 @@ static void rpc_make_runnable(struct rpc_task *task) ...@@ -293,11 +293,6 @@ static void rpc_make_runnable(struct rpc_task *task)
rpc_clear_queued(task); rpc_clear_queued(task);
if (rpc_test_and_set_running(task)) if (rpc_test_and_set_running(task))
return; return;
/* We might have raced */
if (RPC_IS_QUEUED(task)) {
rpc_clear_running(task);
return;
}
if (RPC_IS_ASYNC(task)) { if (RPC_IS_ASYNC(task)) {
int status; int status;
...@@ -607,7 +602,9 @@ void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) ...@@ -607,7 +602,9 @@ void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata)
*/ */
static void __rpc_execute(struct rpc_task *task) static void __rpc_execute(struct rpc_task *task)
{ {
int status = 0; struct rpc_wait_queue *queue;
int task_is_async = RPC_IS_ASYNC(task);
int status = 0;
dprintk("RPC: %5u __rpc_execute flags=0x%x\n", dprintk("RPC: %5u __rpc_execute flags=0x%x\n",
task->tk_pid, task->tk_flags); task->tk_pid, task->tk_flags);
...@@ -647,15 +644,25 @@ static void __rpc_execute(struct rpc_task *task) ...@@ -647,15 +644,25 @@ static void __rpc_execute(struct rpc_task *task)
*/ */
if (!RPC_IS_QUEUED(task)) if (!RPC_IS_QUEUED(task))
continue; continue;
rpc_clear_running(task); /*
if (RPC_IS_ASYNC(task)) { * The queue->lock protects against races with
/* Careful! we may have raced... */ * rpc_make_runnable().
if (RPC_IS_QUEUED(task)) *
return; * Note that once we clear RPC_TASK_RUNNING on an asynchronous
if (rpc_test_and_set_running(task)) * rpc_task, rpc_make_runnable() can assign it to a
return; * different workqueue. We therefore cannot assume that the
* rpc_task pointer may still be dereferenced.
*/
queue = task->tk_waitqueue;
spin_lock_bh(&queue->lock);
if (!RPC_IS_QUEUED(task)) {
spin_unlock_bh(&queue->lock);
continue; continue;
} }
rpc_clear_running(task);
spin_unlock_bh(&queue->lock);
if (task_is_async)
return;
/* sync task: sleep here */ /* sync task: sleep here */
dprintk("RPC: %5u sync task going to sleep\n", task->tk_pid); dprintk("RPC: %5u sync task going to sleep\n", task->tk_pid);
......
...@@ -663,7 +663,7 @@ void xprt_connect(struct rpc_task *task) ...@@ -663,7 +663,7 @@ void xprt_connect(struct rpc_task *task)
xprt, (xprt_connected(xprt) ? "is" : "is not")); xprt, (xprt_connected(xprt) ? "is" : "is not"));
if (!xprt_bound(xprt)) { if (!xprt_bound(xprt)) {
task->tk_status = -EIO; task->tk_status = -EAGAIN;
return; return;
} }
if (!xprt_lock_write(xprt, task)) if (!xprt_lock_write(xprt, task))
......
...@@ -467,7 +467,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, ...@@ -467,7 +467,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
int err, sent = 0; int err, sent = 0;
if (unlikely(!sock)) if (unlikely(!sock))
return -ENOTCONN; return -ENOTSOCK;
clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
if (base != 0) { if (base != 0) {
...@@ -577,6 +577,8 @@ static int xs_udp_send_request(struct rpc_task *task) ...@@ -577,6 +577,8 @@ static int xs_udp_send_request(struct rpc_task *task)
req->rq_svec->iov_base, req->rq_svec->iov_base,
req->rq_svec->iov_len); req->rq_svec->iov_len);
if (!xprt_bound(xprt))
return -ENOTCONN;
status = xs_sendpages(transport->sock, status = xs_sendpages(transport->sock,
xs_addr(xprt), xs_addr(xprt),
xprt->addrlen, xdr, xprt->addrlen, xdr,
...@@ -594,6 +596,10 @@ static int xs_udp_send_request(struct rpc_task *task) ...@@ -594,6 +596,10 @@ static int xs_udp_send_request(struct rpc_task *task)
} }
switch (status) { switch (status) {
case -ENOTSOCK:
status = -ENOTCONN;
/* Should we call xs_close() here? */
break;
case -EAGAIN: case -EAGAIN:
xs_nospace(task); xs_nospace(task);
break; break;
...@@ -693,6 +699,10 @@ static int xs_tcp_send_request(struct rpc_task *task) ...@@ -693,6 +699,10 @@ static int xs_tcp_send_request(struct rpc_task *task)
} }
switch (status) { switch (status) {
case -ENOTSOCK:
status = -ENOTCONN;
/* Should we call xs_close() here? */
break;
case -EAGAIN: case -EAGAIN:
xs_nospace(task); xs_nospace(task);
break; break;
...@@ -1523,7 +1533,7 @@ static void xs_udp_connect_worker4(struct work_struct *work) ...@@ -1523,7 +1533,7 @@ static void xs_udp_connect_worker4(struct work_struct *work)
struct socket *sock = transport->sock; struct socket *sock = transport->sock;
int err, status = -EIO; int err, status = -EIO;
if (xprt->shutdown || !xprt_bound(xprt)) if (xprt->shutdown)
goto out; goto out;
/* Start by resetting any existing state */ /* Start by resetting any existing state */
...@@ -1564,7 +1574,7 @@ static void xs_udp_connect_worker6(struct work_struct *work) ...@@ -1564,7 +1574,7 @@ static void xs_udp_connect_worker6(struct work_struct *work)
struct socket *sock = transport->sock; struct socket *sock = transport->sock;
int err, status = -EIO; int err, status = -EIO;
if (xprt->shutdown || !xprt_bound(xprt)) if (xprt->shutdown)
goto out; goto out;
/* Start by resetting any existing state */ /* Start by resetting any existing state */
...@@ -1648,6 +1658,9 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) ...@@ -1648,6 +1658,9 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
write_unlock_bh(&sk->sk_callback_lock); write_unlock_bh(&sk->sk_callback_lock);
} }
if (!xprt_bound(xprt))
return -ENOTCONN;
/* Tell the socket layer to start connecting... */ /* Tell the socket layer to start connecting... */
xprt->stat.connect_count++; xprt->stat.connect_count++;
xprt->stat.connect_start = jiffies; xprt->stat.connect_start = jiffies;
...@@ -1668,7 +1681,7 @@ static void xs_tcp_connect_worker4(struct work_struct *work) ...@@ -1668,7 +1681,7 @@ static void xs_tcp_connect_worker4(struct work_struct *work)
struct socket *sock = transport->sock; struct socket *sock = transport->sock;
int err, status = -EIO; int err, status = -EIO;
if (xprt->shutdown || !xprt_bound(xprt)) if (xprt->shutdown)
goto out; goto out;
if (!sock) { if (!sock) {
...@@ -1728,7 +1741,7 @@ static void xs_tcp_connect_worker6(struct work_struct *work) ...@@ -1728,7 +1741,7 @@ static void xs_tcp_connect_worker6(struct work_struct *work)
struct socket *sock = transport->sock; struct socket *sock = transport->sock;
int err, status = -EIO; int err, status = -EIO;
if (xprt->shutdown || !xprt_bound(xprt)) if (xprt->shutdown)
goto out; goto out;
if (!sock) { if (!sock) {
......
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