For more information on OCFS2, see the file
<file:Documentation/filesystems/ocfs2.txt>.
+config OCFS2_FS_O2CB
+ tristate "O2CB Kernelspace Clustering"
+ depends on OCFS2_FS
+ default y
+ help
+ OCFS2 includes a simple kernelspace clustering package, the OCFS2
+ Cluster Base. It only requires a very small userspace component
+ to configure it. This comes with the standard ocfs2-tools package.
+ O2CB is limited to maintaining a cluster for OCFS2 file systems.
+ It cannot manage any other cluster applications.
+
+ It is always safe to say Y here, as the clustering method is
+ run-time selectable.
+
+config OCFS2_FS_USERSPACE_CLUSTER
+ tristate "OCFS2 Userspace Clustering"
+ depends on OCFS2_FS && DLM
+ default y
+ help
+ This option will allow OCFS2 to use userspace clustering services
+ in conjunction with the DLM in fs/dlm. If you are using a
+ userspace cluster manager, say Y here.
+
+ It is safe to say Y, as the clustering method is run-time
+ selectable.
+
config OCFS2_DEBUG_MASKLOG
bool "OCFS2 logging support"
depends on OCFS2_FS
config UDF_FS
tristate "UDF file system support"
+ select CRC_ITU_T
help
This is the new file system used on some CD-ROMs and DVDs. Say Y if
you intend to mount DVD discs or CDRW's written in packet mode, or
If unsure, say N.
- config NFS_DIRECTIO
- bool "Allow direct I/O on NFS files"
- depends on NFS_FS
- help
- This option enables applications to perform uncached I/O on files
- in NFS file systems using the O_DIRECT open() flag. When O_DIRECT
- is set for a file, its data is not cached in the system's page
- cache. Data is moved to and from user-level application buffers
- directly. Unlike local disk-based file systems, NFS O_DIRECT has
- no alignment restrictions.
-
- Unless your program is designed to use O_DIRECT properly, you are
- much better off allowing the NFS client to manage data caching for
- you. Misusing O_DIRECT can cause poor server performance or network
- storms. This kernel build option defaults OFF to avoid exposing
- system administrators unwittingly to a potentially hazardous
- feature.
-
- For more details on NFS O_DIRECT, see fs/nfs/direct.c.
-
- If unsure, say N. This reduces the size of the NFS client, and
- causes open() to return EINVAL if a file residing in NFS is
- opened with the O_DIRECT flag.
-
config NFSD
tristate "NFS server support"
depends on INET
If you want your Linux box to mount its whole root file system (the
one containing the directory /) from some other computer over the
net via NFS (presumably because your box doesn't have a hard disk),
- say Y. Read <file:Documentation/nfsroot.txt> for details. It is
- likely that in this case, you also want to say Y to "Kernel level IP
- autoconfiguration" so that your box can discover its network address
- at boot time.
+ say Y. Read <file:Documentation/filesystems/nfsroot.txt> for
+ details. It is likely that in this case, you also want to say Y to
+ "Kernel level IP autoconfiguration" so that your box can discover
+ its network address at boot time.
Most people say N here.
tristate
depends on SUNRPC && INFINIBAND && EXPERIMENTAL
default SUNRPC && INFINIBAND
+ help
+ This option enables an RPC client transport capability that
+ allows the NFS client to mount servers via an RDMA-enabled
+ transport.
+
+ To compile RPC client RDMA transport support as a module,
+ choose M here: the module will be called xprtrdma.
+
+ If unsure, say N.
config SUNRPC_BIND34
bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
+ default n
help
- Provides kernel support for querying rpcbind servers via versions 3
- and 4 of the rpcbind protocol. The kernel automatically falls back
- to version 2 if a remote rpcbind service does not support versions
- 3 or 4.
+ RPC requests over IPv6 networks require support for larger
+ addresses when performing an RPC bind. Sun added support for
+ IPv6 addressing by creating two new versions of the rpcbind
+ protocol (RFC 1833).
+
+ This option enables support in the kernel RPC client for
+ querying rpcbind servers via versions 3 and 4 of the rpcbind
+ protocol. The kernel automatically falls back to version 2
+ if a remote rpcbind service does not support versions 3 or 4.
+ By themselves, these new versions do not provide support for
+ RPC over IPv6, but the new protocol versions are necessary to
+ support it.
If unsure, say N to get traditional behavior (version 2 rpcbind
requests only).
select CRYPTO_DES
select CRYPTO_CBC
help
- Provides for secure RPC calls by means of a gss-api
- mechanism based on Kerberos V5. This is required for
- NFSv4.
+ Choose Y here to enable Secure RPC using the Kerberos version 5
+ GSS-API mechanism (RFC 1964).
- Note: Requires an auxiliary userspace daemon which may be found on
- http://www.citi.umich.edu/projects/nfsv4/
+ Secure RPC calls with Kerberos require an auxiliary user-space
+ daemon which may be found in the Linux nfs-utils package
+ available from http://linux-nfs.org/. In addition, user-space
+ Kerberos support should be installed.
If unsure, say N.
select CRYPTO_CAST5
select CRYPTO_CBC
help
- Provides for secure RPC calls by means of a gss-api
- mechanism based on the SPKM3 public-key mechanism.
+ Choose Y here to enable Secure RPC using the SPKM3 public key
+ GSS-API mechansim (RFC 2025).
- Note: Requires an auxiliary userspace daemon which may be found on
- http://www.citi.umich.edu/projects/nfsv4/
+ Secure RPC calls with SPKM3 require an auxiliary userspace
+ daemon which may be found in the Linux nfs-utils package
+ available from http://linux-nfs.org/.
If unsure, say N.
if (nd->flags & LOOKUP_DIRECTORY)
return 0;
/* Are we trying to write to a read only partition? */
- if (IS_RDONLY(dir) && (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE)))
+ if (__mnt_is_readonly(nd->path.mnt) &&
+ (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE)))
return 0;
return 1;
}
if (!NFS_PROTO(inode)->access)
goto out_notsup;
- cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+ cred = rpc_lookup_cred();
if (!IS_ERR(cred)) {
res = nfs_do_access(inode, cred, mask);
put_rpccred(cred);
.write = do_sync_write,
.aio_read = nfs_file_read,
.aio_write = nfs_file_write,
+#ifdef CONFIG_MMU
.mmap = nfs_file_mmap,
+#else
+ .mmap = generic_file_mmap,
+#endif
.open = nfs_file_open,
.flush = nfs_file_flush,
.release = nfs_file_release,
ssize_t result;
size_t count = iov_length(iov, nr_segs);
- #ifdef CONFIG_NFS_DIRECTIO
if (iocb->ki_filp->f_flags & O_DIRECT)
return nfs_file_direct_read(iocb, iov, nr_segs, pos);
- #endif
dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
.write_end = nfs_write_end,
.invalidatepage = nfs_invalidate_page,
.releasepage = nfs_release_page,
- #ifdef CONFIG_NFS_DIRECTIO
.direct_IO = nfs_direct_IO,
- #endif
.launder_page = nfs_launder_page,
};
ssize_t result;
size_t count = iov_length(iov, nr_segs);
- #ifdef CONFIG_NFS_DIRECTIO
if (iocb->ki_filp->f_flags & O_DIRECT)
return nfs_file_direct_write(iocb, iov, nr_segs, pos);
- #endif
dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
lock_kernel();
/* Use local locking if mounted with "-onolock" */
- if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) {
+ if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
status = NFS_PROTO(inode)->lock(filp, cmd, fl);
- /* If we were signalled we still need to ensure that
- * we clean up any state on the server. We therefore
- * record the lock call as having succeeded in order to
- * ensure that locks_remove_posix() cleans it out when
- * the process exits.
- */
- if (status == -EINTR || status == -ERESTARTSYS)
- do_vfs_lock(filp, fl);
- } else
+ else
status = do_vfs_lock(filp, fl);
unlock_kernel();
if (status < 0)
ctx->cred = get_rpccred(cred);
ctx->state = NULL;
ctx->lockowner = current->files;
+ ctx->flags = 0;
ctx->error = 0;
ctx->dir_cookie = 0;
atomic_set(&ctx->count, 1);
static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait)
{
- struct inode *inode = ctx->path.dentry->d_inode;
+ struct inode *inode;
+ if (ctx == NULL)
+ return;
+
+ inode = ctx->path.dentry->d_inode;
if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
return;
list_del(&ctx->list);
struct nfs_open_context *ctx;
struct rpc_cred *cred;
- cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+ cred = rpc_lookup_cred();
if (IS_ERR(cred))
return PTR_ERR(cred);
ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred);
kmem_cache_destroy(nfs_inode_cachep);
}
+ struct workqueue_struct *nfsiod_workqueue;
+
+ /*
+ * start up the nfsiod workqueue
+ */
+ static int nfsiod_start(void)
+ {
+ struct workqueue_struct *wq;
+ dprintk("RPC: creating workqueue nfsiod\n");
+ wq = create_singlethread_workqueue("nfsiod");
+ if (wq == NULL)
+ return -ENOMEM;
+ nfsiod_workqueue = wq;
+ return 0;
+ }
+
+ /*
+ * Destroy the nfsiod workqueue
+ */
+ static void nfsiod_stop(void)
+ {
+ struct workqueue_struct *wq;
+
+ wq = nfsiod_workqueue;
+ if (wq == NULL)
+ return;
+ nfsiod_workqueue = NULL;
+ destroy_workqueue(wq);
+ }
+
/*
* Initialize NFS
*/
{
int err;
+ err = nfsiod_start();
+ if (err)
+ goto out6;
+
err = nfs_fs_proc_init();
if (err)
goto out5;
out4:
nfs_fs_proc_exit();
out5:
+ nfsiod_stop();
+ out6:
return err;
}
#endif
unregister_nfs_fs();
nfs_fs_proc_exit();
+ nfsiod_stop();
}
/* Not quite true; I just maintain it */
return sec_flavours[i].str;
}
+ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
+ int showdefaults)
+ {
+ struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address;
+
+ switch (sap->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+ seq_printf(m, ",mountaddr=" NIPQUAD_FMT,
+ NIPQUAD(sin->sin_addr.s_addr));
+ break;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+ seq_printf(m, ",mountaddr=" NIP6_FMT,
+ NIP6(sin6->sin6_addr));
+ break;
+ }
+ default:
+ if (showdefaults)
+ seq_printf(m, ",mountaddr=unspecified");
+ }
+
+ if (nfss->mountd_version || showdefaults)
+ seq_printf(m, ",mountvers=%u", nfss->mountd_version);
+ if (nfss->mountd_port || showdefaults)
+ seq_printf(m, ",mountport=%u", nfss->mountd_port);
+
+ switch (nfss->mountd_protocol) {
+ case IPPROTO_UDP:
+ seq_printf(m, ",mountproto=udp");
+ break;
+ case IPPROTO_TCP:
+ seq_printf(m, ",mountproto=tcp");
+ break;
+ default:
+ if (showdefaults)
+ seq_printf(m, ",mountproto=auto");
+ }
+ }
+
/*
* Describe the mount options in force on this server representation
*/
- static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
+ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
+ int showdefaults)
{
static const struct proc_nfs_info {
int flag;
const char *nostr;
} nfs_info[] = {
{ NFS_MOUNT_SOFT, ",soft", ",hard" },
+ { NFS_MOUNT_INTR, ",intr", ",nointr" },
+ { NFS_MOUNT_POSIX, ",posix", "" },
{ NFS_MOUNT_NOCTO, ",nocto", "" },
{ NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", "" },
};
const struct proc_nfs_info *nfs_infop;
struct nfs_client *clp = nfss->nfs_client;
-
- seq_printf(m, ",vers=%d", clp->rpc_ops->version);
- seq_printf(m, ",rsize=%d", nfss->rsize);
- seq_printf(m, ",wsize=%d", nfss->wsize);
+ u32 version = clp->rpc_ops->version;
+
+ seq_printf(m, ",vers=%u", version);
+ seq_printf(m, ",rsize=%u", nfss->rsize);
+ seq_printf(m, ",wsize=%u", nfss->wsize);
+ if (nfss->bsize != 0)
+ seq_printf(m, ",bsize=%u", nfss->bsize);
+ seq_printf(m, ",namlen=%u", nfss->namelen);
if (nfss->acregmin != 3*HZ || showdefaults)
- seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
+ seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ);
if (nfss->acregmax != 60*HZ || showdefaults)
- seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
+ seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ);
if (nfss->acdirmin != 30*HZ || showdefaults)
- seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
+ seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ);
if (nfss->acdirmax != 60*HZ || showdefaults)
- seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
+ seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ);
for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
if (nfss->flags & nfs_infop->flag)
seq_puts(m, nfs_infop->str);
}
seq_printf(m, ",proto=%s",
rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO));
+ if (version == 4) {
+ if (nfss->port != NFS_PORT)
+ seq_printf(m, ",port=%u", nfss->port);
+ } else
+ if (nfss->port)
+ seq_printf(m, ",port=%u", nfss->port);
+
seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ);
seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries);
seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
+
+ if (version != 4)
+ nfs_show_mountd_options(m, nfss, showdefaults);
+
+ #ifdef CONFIG_NFS_V4
+ if (clp->rpc_ops->version == 4)
+ seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
+ #endif
}
/*
seq_printf(m, "\n\tcaps:\t");
seq_printf(m, "caps=0x%x", nfss->caps);
- seq_printf(m, ",wtmult=%d", nfss->wtmult);
- seq_printf(m, ",dtsize=%d", nfss->dtsize);
- seq_printf(m, ",bsize=%d", nfss->bsize);
- seq_printf(m, ",namelen=%d", nfss->namelen);
+ seq_printf(m, ",wtmult=%u", nfss->wtmult);
+ seq_printf(m, ",dtsize=%u", nfss->dtsize);
+ seq_printf(m, ",bsize=%u", nfss->bsize);
+ seq_printf(m, ",namlen=%u", nfss->namelen);
#ifdef CONFIG_NFS_V4
if (nfss->nfs_client->rpc_ops->version == 4) {
/*
* Display security flavor in effect for this mount
*/
- seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
+ seq_printf(m, "\n\tsec:\tflavor=%u", auth->au_ops->au_flavor);
if (auth->au_flavor)
- seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
+ seq_printf(m, ",pseudoflavor=%u", auth->au_flavor);
/*
* Display superblock I/O counters
struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb);
struct rpc_clnt *rpc;
- shrink_submounts(vfsmnt, &nfs_automount_list);
-
if (!(flags & MNT_FORCE))
return;
/* -EIO all pending I/O */
switch (addr->sa_family) {
case AF_INET: {
struct sockaddr_in *sa = (struct sockaddr_in *)addr;
- return sa->sin_addr.s_addr != INADDR_ANY;
+ return sa->sin_addr.s_addr != htonl(INADDR_ANY);
}
case AF_INET6: {
struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr;
struct nfs_parsed_mount_data *mnt)
{
char *p, *string, *secdata;
- unsigned short port = 0;
int rc;
if (!raw) {
return 0;
if (option < 0 || option > 65535)
return 0;
- port = option;
+ mnt->nfs_server.port = option;
break;
case Opt_rsize:
if (match_int(args, &mnt->rsize))
}
}
- nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, port);
+ nfs_set_port((struct sockaddr *)&mnt->nfs_server.address,
+ mnt->nfs_server.port);
return 1;
args->acregmax = 60;
args->acdirmin = 30;
args->acdirmax = 60;
+ args->mount_server.port = 0; /* autobind unless user sets port */
args->mount_server.protocol = XPRT_TRANSPORT_UDP;
+ args->nfs_server.port = 0; /* autobind unless user sets port */
args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
switch (data->version) {
args->flags = data->flags;
args->rsize = data->rsize;
args->wsize = data->wsize;
- args->flags = data->flags;
args->timeo = data->timeo;
args->retrans = data->retrans;
args->acregmin = data->acregmin;
args->namlen = data->namlen;
args->bsize = data->bsize;
args->auth_flavors[0] = data->pseudoflavor;
+ if (!args->nfs_server.hostname)
+ goto out_nomem;
/*
* The legacy version 6 binary mount data from userspace has a
len = c - dev_name;
/* N.B. caller will free nfs_server.hostname in all cases */
args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
+ if (!args->nfs_server.hostname)
+ goto out_nomem;
c++;
if (strlen(c) > NFS_MAXPATHLEN)
return -EPROTONOSUPPORT;
#endif /* !CONFIG_NFS_V3 */
+ out_nomem:
+ dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n");
+ return -ENOMEM;
+
out_no_address:
dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
return -EINVAL;
nfs_initialise_sb(sb);
}
- /*
- * If the user didn't specify a port, set the port number to
- * the NFS version 4 default port.
- */
- static void nfs4_default_port(struct sockaddr *sap)
- {
- switch (sap->sa_family) {
- case AF_INET: {
- struct sockaddr_in *ap = (struct sockaddr_in *)sap;
- if (ap->sin_port == 0)
- ap->sin_port = htons(NFS_PORT);
- break;
- }
- case AF_INET6: {
- struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap;
- if (ap->sin6_port == 0)
- ap->sin6_port = htons(NFS_PORT);
- break;
- }
- }
- }
-
/*
* Validate NFSv4 mount options
*/
args->acregmax = 60;
args->acdirmin = 30;
args->acdirmax = 60;
+ args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */
args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
switch (data->version) {
&args->nfs_server.address))
goto out_no_address;
- nfs4_default_port((struct sockaddr *)
- &args->nfs_server.address);
-
switch (data->auth_flavourlen) {
case 0:
args->auth_flavors[0] = RPC_AUTH_UNIX;
&args->nfs_server.address))
return -EINVAL;
- nfs4_default_port((struct sockaddr *)
- &args->nfs_server.address);
-
switch (args->auth_flavor_len) {
case 0:
args->auth_flavors[0] = RPC_AUTH_UNIX;
return -ENAMETOOLONG;
/* N.B. caller will free nfs_server.hostname in all cases */
args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
+ if (!args->nfs_server.hostname)
+ goto out_nomem;
c++; /* step over the ':' */
len = strlen(c);
if (len > NFS4_MAXPATHLEN)
return -ENAMETOOLONG;
args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL);
+ if (!args->nfs_server.export_path)
+ goto out_nomem;
dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path);
data->auth_flavourlen);
return -EINVAL;
+ out_nomem:
+ dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n");
+ return -ENOMEM;
+
out_no_address:
dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
return -EINVAL;
gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
{
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
- struct gss_cl_ctx *old;
- old = gss_cred->gc_ctx;
+ if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+ return;
+ gss_get_ctx(ctx);
rcu_assign_pointer(gss_cred->gc_ctx, ctx);
set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+ smp_mb__before_clear_bit();
clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
- if (old)
- gss_put_ctx(old);
- }
-
- static int
- gss_cred_is_uptodate_ctx(struct rpc_cred *cred)
- {
- struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
- int res = 0;
-
- rcu_read_lock();
- if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx)
- res = 1;
- rcu_read_unlock();
- return res;
}
static const void *
BUG_ON(!list_empty(&gss_msg->list));
if (gss_msg->ctx != NULL)
gss_put_ctx(gss_msg->ctx);
+ rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
kfree(gss_msg);
}
spin_lock(&inode->i_lock);
if (gss_msg->ctx)
- gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
+ gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
else
task->tk_status = gss_msg->msg.errno;
gss_cred->gc_upcall = NULL;
static struct gss_upcall_msg *
gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred)
{
+ struct gss_cred *gss_cred = container_of(cred,
+ struct gss_cred, gc_base);
struct gss_upcall_msg *gss_new, *gss_msg;
+ uid_t uid = cred->cr_uid;
- gss_new = gss_alloc_msg(gss_auth, cred->cr_uid);
+ /* Special case: rpc.gssd assumes that uid == 0 implies machine creds */
+ if (gss_cred->gc_machine_cred != 0)
+ uid = 0;
+
+ gss_new = gss_alloc_msg(gss_auth, uid);
if (gss_new == NULL)
return ERR_PTR(-ENOMEM);
gss_msg = gss_add_msg(gss_auth, gss_new);
}
spin_lock(&inode->i_lock);
if (gss_cred->gc_upcall != NULL)
- rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL);
- else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
+ rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
+ else if (gss_msg->ctx != NULL) {
+ gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
+ gss_cred->gc_upcall = NULL;
+ rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
+ } else if (gss_msg->msg.errno >= 0) {
task->tk_timeout = 0;
gss_cred->gc_upcall = gss_msg;
/* gss_upcall_callback will release the reference to gss_upcall_msg */
atomic_inc(&gss_msg->count);
- rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL);
+ rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
} else
err = gss_msg->msg.errno;
spin_unlock(&inode->i_lock);
schedule();
}
if (gss_msg->ctx)
- gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx));
+ gss_cred_set_ctx(cred, gss_msg->ctx);
else
err = gss_msg->msg.errno;
spin_unlock(&inode->i_lock);
gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
if (!gss_auth->mech) {
printk(KERN_WARNING "%s: Pseudoflavor %d not found!\n",
- __FUNCTION__, flavor);
+ __func__, flavor);
goto err_free;
}
gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
struct rpc_task *task;
if (gss_cred->gc_ctx == NULL ||
- gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY)
+ test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
return 0;
gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY;
* by the RPC call or by the put_rpccred() below */
get_rpccred(cred);
- task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC);
+ task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT);
if (!IS_ERR(task))
rpc_put_task(task);
*/
cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW;
cred->gc_service = gss_auth->service;
+ cred->gc_machine_cred = acred->machine_cred;
kref_get(&gss_auth->kref);
return &cred->gc_base;
{
struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
- /*
- * If the searchflags have set RPCAUTH_LOOKUP_NEW, then
- * we don't really care if the credential has expired or not,
- * since the caller should be prepared to reinitialise it.
- */
- if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
+ if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
goto out;
/* Don't match with creds that have expired. */
- if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+ if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+ return 0;
+ if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
return 0;
out:
+ if (acred->machine_cred != gss_cred->gc_machine_cred)
+ return 0;
return (rc->cr_uid == acred->uid);
}
return NULL;
}
+ static int gss_renew_cred(struct rpc_task *task)
+ {
+ struct rpc_cred *oldcred = task->tk_msg.rpc_cred;
+ struct gss_cred *gss_cred = container_of(oldcred,
+ struct gss_cred,
+ gc_base);
+ struct rpc_auth *auth = oldcred->cr_auth;
+ struct auth_cred acred = {
+ .uid = oldcred->cr_uid,
+ .machine_cred = gss_cred->gc_machine_cred,
+ };
+ struct rpc_cred *new;
+
+ new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
+ if (IS_ERR(new))
+ return PTR_ERR(new);
+ task->tk_msg.rpc_cred = new;
+ put_rpccred(oldcred);
+ return 0;
+ }
+
/*
* Refresh credentials. XXX - finish
*/
static int
gss_refresh(struct rpc_task *task)
{
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ int ret = 0;
+
+ if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
+ !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
+ ret = gss_renew_cred(task);
+ if (ret < 0)
+ goto out;
+ cred = task->tk_msg.rpc_cred;
+ }
- if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred))
- return gss_refresh_upcall(task);
- return 0;
+ if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+ ret = gss_refresh_upcall(task);
+ out:
+ return ret;
}
/* Dummy refresh routine: used only when destroying the context */
static const struct rpc_authops authgss_ops = {
.owner = THIS_MODULE,
.au_flavor = RPC_AUTH_GSS,
- #ifdef RPC_DEBUG
.au_name = "RPCSEC_GSS",
- #endif
.create = gss_create,
.destroy = gss_destroy,
.lookup_cred = gss_lookup_cred,
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
.cr_init = gss_cred_init,
+ .crbind = rpcauth_generic_bind_cred,
.crmatch = gss_match,
.crmarshal = gss_marshal,
.crrefresh = gss_refresh,
static const struct rpc_credops gss_nullops = {
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
+ .crbind = rpcauth_generic_bind_cred,
.crmatch = gss_match,
.crmarshal = gss_marshal,
.crrefresh = gss_refresh_null,
#define dprint_status(t) \
dprintk("RPC: %5u %s (status %d)\n", t->tk_pid, \
- __FUNCTION__, t->tk_status)
+ __func__, t->tk_status)
/*
* All RPC clients are linked into this list
};
char servername[48];
- xprt = xprt_create_transport(&xprtargs);
- if (IS_ERR(xprt))
- return (struct rpc_clnt *)xprt;
-
/*
* If the caller chooses not to specify a hostname, whip
* up a string representation of the passed-in address.
out_no_stats:
kfree(new);
out_no_clnt:
- dprintk("RPC: %s: returned error %d\n", __FUNCTION__, err);
+ dprintk("RPC: %s: returned error %d\n", __func__, err);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(rpc_clone_client);
* @msg: RPC call parameters
* @flags: RPC call flags
*/
- int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
+ int rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags)
{
struct rpc_task *task;
struct rpc_task_setup task_setup_data = {
* @data: user call data
*/
int
- rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
+ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags,
const struct rpc_call_ops *tk_ops, void *data)
{
struct rpc_task *task;
}
printk(KERN_ERR "%s: status=%d, but no request slot, exiting\n",
- __FUNCTION__, status);
+ __func__, status);
rpc_exit(task, -EIO);
return;
}
*/
if (task->tk_rqstp) {
printk(KERN_ERR "%s: status=%d, request allocated anyway\n",
- __FUNCTION__, status);
+ __func__, status);
xprt_release(task);
}
break;
default:
printk(KERN_ERR "%s: unrecognized error %d, exiting\n",
- __FUNCTION__, status);
+ __func__, status);
break;
}
rpc_exit(task, status);
if (task->tk_msg.rpc_proc->p_decode != NULL)
return;
task->tk_action = rpc_exit_task;
- rpc_wake_up_task(task);
+ rpc_wake_up_queued_task(&task->tk_xprt->pending, task);
}
/*
case -ETIMEDOUT:
task->tk_action = call_timeout;
if (task->tk_client->cl_discrtry)
- xprt_force_disconnect(task->tk_xprt);
+ xprt_conditional_disconnect(task->tk_xprt,
+ req->rq_connect_cookie);
break;
case -ECONNREFUSED:
case -ENOTCONN:
clnt->cl_protname, clnt->cl_server);
}
rpc_force_rebind(clnt);
+ /*
+ * Did our request time out due to an RPCSEC_GSS out-of-sequence
+ * event? RFC2203 requires the server to drop all such requests.
+ */
+ rpcauth_invalcred(task);
retry:
clnt->cl_stats->rpcretrans++;
task->tk_flags &= ~RPC_CALL_MAJORSEEN;
}
- if (task->tk_status < 12) {
- if (!RPC_IS_SOFT(task)) {
- task->tk_action = call_bind;
- clnt->cl_stats->rpcretrans++;
- goto out_retry;
- }
- dprintk("RPC: %s: too small RPC reply size (%d bytes)\n",
- clnt->cl_protname, task->tk_status);
- task->tk_action = call_timeout;
- goto out_retry;
- }
-
/*
* Ensure that we see all writes made by xprt_complete_rqst()
* before it changed req->rq_received.
WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
sizeof(req->rq_rcv_buf)) != 0);
+ if (req->rq_rcv_buf.len < 12) {
+ if (!RPC_IS_SOFT(task)) {
+ task->tk_action = call_bind;
+ clnt->cl_stats->rpcretrans++;
+ goto out_retry;
+ }
+ dprintk("RPC: %s: too small RPC reply size (%d bytes)\n",
+ clnt->cl_protname, task->tk_status);
+ task->tk_action = call_timeout;
+ goto out_retry;
+ }
+
/* Verify the RPC header */
p = call_verify(task);
if (IS_ERR(p)) {
task->tk_status);
return;
out_retry:
- req->rq_received = req->rq_private_buf.len = 0;
task->tk_status = 0;
- if (task->tk_client->cl_discrtry)
- xprt_force_disconnect(task->tk_xprt);
+ /* Note: call_verify() may have freed the RPC slot */
+ if (task->tk_rqstp == req) {
+ req->rq_received = req->rq_rcv_buf.len = 0;
+ if (task->tk_client->cl_discrtry)
+ xprt_conditional_disconnect(task->tk_xprt,
+ req->rq_connect_cookie);
+ }
}
/*
* undefined results
*/
dprintk("RPC: %5u %s: XDR representation not a multiple of"
- " 4 bytes: 0x%x\n", task->tk_pid, __FUNCTION__,
+ " 4 bytes: 0x%x\n", task->tk_pid, __func__,
task->tk_rqstp->rq_rcv_buf.len);
goto out_eio;
}
if ((n = ntohl(*p++)) != RPC_REPLY) {
dprintk("RPC: %5u %s: not an RPC reply: %x\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
goto out_garbage;
}
if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
case RPC_MISMATCH:
dprintk("RPC: %5u %s: RPC call version "
"mismatch!\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
error = -EPROTONOSUPPORT;
goto out_err;
default:
dprintk("RPC: %5u %s: RPC call rejected, "
"unknown error: %x\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
goto out_eio;
}
if (--len < 0)
break;
task->tk_cred_retry--;
dprintk("RPC: %5u %s: retry stale creds\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
rpcauth_invalcred(task);
/* Ensure we obtain a new XID! */
xprt_release(task);
break;
task->tk_garb_retry--;
dprintk("RPC: %5u %s: retry garbled creds\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
task->tk_action = call_bind;
goto out_retry;
case RPC_AUTH_TOOWEAK:
break;
default:
dprintk("RPC: %5u %s: unknown auth error: %x\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
error = -EIO;
}
dprintk("RPC: %5u %s: call rejected %d\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
goto out_err;
}
if (!(p = rpcauth_checkverf(task, p))) {
dprintk("RPC: %5u %s: auth check failed\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto out_garbage; /* bad verifier, retry */
}
len = p - (__be32 *)iov->iov_base - 1;
return p;
case RPC_PROG_UNAVAIL:
dprintk("RPC: %5u %s: program %u is unsupported by server %s\n",
- task->tk_pid, __FUNCTION__,
+ task->tk_pid, __func__,
(unsigned int)task->tk_client->cl_prog,
task->tk_client->cl_server);
error = -EPFNOSUPPORT;
goto out_err;
case RPC_PROG_MISMATCH:
dprintk("RPC: %5u %s: program %u, version %u unsupported by "
- "server %s\n", task->tk_pid, __FUNCTION__,
+ "server %s\n", task->tk_pid, __func__,
(unsigned int)task->tk_client->cl_prog,
(unsigned int)task->tk_client->cl_vers,
task->tk_client->cl_server);
case RPC_PROC_UNAVAIL:
dprintk("RPC: %5u %s: proc %p unsupported by program %u, "
"version %u on server %s\n",
- task->tk_pid, __FUNCTION__,
+ task->tk_pid, __func__,
task->tk_msg.rpc_proc,
task->tk_client->cl_prog,
task->tk_client->cl_vers,
goto out_err;
case RPC_GARBAGE_ARGS:
dprintk("RPC: %5u %s: server saw garbage\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
break; /* retry */
default:
dprintk("RPC: %5u %s: server accept status: %x\n",
- task->tk_pid, __FUNCTION__, n);
+ task->tk_pid, __func__, n);
/* Also retry */
}
if (task->tk_garb_retry) {
task->tk_garb_retry--;
dprintk("RPC: %5u %s: retrying\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
task->tk_action = call_bind;
out_retry:
return ERR_PTR(-EAGAIN);
out_err:
rpc_exit(task, error);
dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
- __FUNCTION__, error);
+ __func__, error);
return ERR_PTR(error);
out_overflow:
dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid,
- __FUNCTION__);
+ __func__);
goto out_garbage;
}
proc = -1;
if (RPC_IS_QUEUED(t))
- rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);
+ rpc_waitq = rpc_qname(t->tk_waitqueue);
printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",
t->tk_pid, proc,
int status;
dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
- __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+ __func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
sizeof(*sin), prot, 2, 0);
struct rpcb_info *info;
dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
- task->tk_pid, __FUNCTION__,
+ task->tk_pid, __func__,
clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);
/* Autobind on cloned rpc clients is discouraged */
if (xprt_test_and_set_binding(xprt)) {
status = -EAGAIN; /* tell caller to check again */
dprintk("RPC: %5u %s: waiting for another binder\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nowake;
}
/* Put self on queue before sending rpcbind request, in case
* rpcb_getport_done completes before we return from rpc_run_task */
- rpc_sleep_on(&xprt->binding, task, NULL, NULL);
+ rpc_sleep_on(&xprt->binding, task, NULL);
/* Someone else may have bound if we slept */
if (xprt_bound(xprt)) {
status = 0;
dprintk("RPC: %5u %s: already bound\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nofree;
}
default:
status = -EAFNOSUPPORT;
dprintk("RPC: %5u %s: bad address family\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nofree;
}
if (info[xprt->bind_index].rpc_proc == NULL) {
xprt->bind_index = 0;
status = -EPFNOSUPPORT;
dprintk("RPC: %5u %s: no more getport versions available\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nofree;
}
bind_version = info[xprt->bind_index].rpc_vers;
dprintk("RPC: %5u %s: trying rpcbind version %u\n",
- task->tk_pid, __FUNCTION__, bind_version);
+ task->tk_pid, __func__, bind_version);
rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
bind_version, 0);
if (IS_ERR(rpcb_clnt)) {
status = PTR_ERR(rpcb_clnt);
dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
- task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
+ task->tk_pid, __func__, PTR_ERR(rpcb_clnt));
goto bailout_nofree;
}
if (!map) {
status = -ENOMEM;
dprintk("RPC: %5u %s: no memory available\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout_nofree;
}
map->r_prog = clnt->cl_prog;
if (IS_ERR(child)) {
status = -EIO;
dprintk("RPC: %5u %s: rpc_run_task failed\n",
- task->tk_pid, __FUNCTION__);
+ task->tk_pid, __func__);
goto bailout;
}
rpc_put_task(child);
#endif
- /*
- * How many times to try sending a request on a socket before waiting
- * for the socket buffer to clear.
- */
- #define XS_SENDMSG_RETRY (10U)
-
/*
* Time out for an RPC UDP socket connect. UDP socket connects are
* synchronous, but we set a timeout anyway in case of resource
return sent;
}
+ static void xs_nospace_callback(struct rpc_task *task)
+ {
+ struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
+
+ transport->inet->sk_write_pending--;
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+ }
+
/**
* xs_nospace - place task on wait queue if transmit was incomplete
* @task: task to put to sleep
task->tk_pid, req->rq_slen - req->rq_bytes_sent,
req->rq_slen);
- if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
- /* Protect against races with write_space */
- spin_lock_bh(&xprt->transport_lock);
-
- /* Don't race with disconnect */
- if (!xprt_connected(xprt))
- task->tk_status = -ENOTCONN;
- else if (test_bit(SOCK_NOSPACE, &transport->sock->flags))
- xprt_wait_for_buffer_space(task);
+ /* Protect against races with write_space */
+ spin_lock_bh(&xprt->transport_lock);
+
+ /* Don't race with disconnect */
+ if (xprt_connected(xprt)) {
+ if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
+ /*
+ * Notify TCP that we're limited by the application
+ * window size
+ */
+ set_bit(SOCK_NOSPACE, &transport->sock->flags);
+ transport->inet->sk_write_pending++;
+ /* ...and wait for more buffer space */
+ xprt_wait_for_buffer_space(task, xs_nospace_callback);
+ }
+ } else {
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+ task->tk_status = -ENOTCONN;
+ }
- spin_unlock_bh(&xprt->transport_lock);
- } else
- /* Keep holding the socket if it is blocked */
- rpc_delay(task, HZ>>4);
+ spin_unlock_bh(&xprt->transport_lock);
}
/**
}
switch (status) {
+ case -EAGAIN:
+ xs_nospace(task);
+ break;
case -ENETUNREACH:
case -EPIPE:
case -ECONNREFUSED:
/* When the server has died, an ICMP port unreachable message
* prompts ECONNREFUSED. */
- break;
- case -EAGAIN:
- xs_nospace(task);
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
break;
default:
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
dprintk("RPC: sendmsg returned unrecognized error %d\n",
-status);
- break;
}
return status;
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
struct xdr_buf *xdr = &req->rq_snd_buf;
int status;
- unsigned int retry = 0;
xs_encode_tcp_record_marker(&req->rq_snd_buf);
return 0;
}
+ if (status != 0)
+ continue;
status = -EAGAIN;
- if (retry++ > XS_SENDMSG_RETRY)
- break;
+ break;
}
switch (status) {
case -ENOTCONN:
case -EPIPE:
status = -ENOTCONN;
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
break;
default:
dprintk("RPC: sendmsg returned unrecognized error %d\n",
-status);
+ clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
xs_tcp_shutdown(xprt);
- break;
}
return status;
{
struct rpc_xprt *xprt;
read_descriptor_t rd_desc;
+ int read;
dprintk("RPC: xs_tcp_data_ready...\n");
/* We use rd_desc to pass struct xprt to xs_tcp_data_recv */
rd_desc.arg.data = xprt;
- rd_desc.count = 65536;
- tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);
+ do {
+ rd_desc.count = 65536;
+ read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);
+ } while (read > 0);
out:
read_unlock(&sk->sk_callback_lock);
}
break;
case TCP_FIN_WAIT1:
/* The client initiated a shutdown of the socket */
+ xprt->connect_cookie++;
xprt->reestablish_timeout = 0;
set_bit(XPRT_CLOSING, &xprt->state);
smp_mb__before_clear_bit();
set_bit(XPRT_CLOSING, &xprt->state);
xprt_force_disconnect(xprt);
case TCP_SYN_SENT:
+ xprt->connect_cookie++;
case TCP_CLOSING:
/*
* If the server closed down the connection, make sure that
if (unlikely(!(sock = sk->sk_socket)))
goto out;
+ clear_bit(SOCK_NOSPACE, &sock->flags);
+
if (unlikely(!(xprt = xprt_from_sock(sk))))
goto out;
- if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)))
+ if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
goto out;
xprt_write_space(xprt);
if (unlikely(!(sock = sk->sk_socket)))
goto out;
+ clear_bit(SOCK_NOSPACE, &sock->flags);
+
if (unlikely(!(xprt = xprt_from_sock(sk))))
goto out;
- if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)))
+ if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
goto out;
xprt_write_space(xprt);
nloop++;
} while (err == -EADDRINUSE && nloop != 2);
dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n",
- __FUNCTION__, NIPQUAD(myaddr.sin_addr),
+ __func__, NIPQUAD(myaddr.sin_addr),
port, err ? "failed" : "ok", err);
return err;
}