diff -u --recursive --new-file linux-2.4.21-acpi/fs/lockd/clntproc.c linux-2.4.21-15-seekdir/fs/lockd/clntproc.c --- linux-2.4.21-acpi/fs/lockd/clntproc.c 2001-10-11 07:52:18.000000000 -0700 +++ linux-2.4.21-15-seekdir/fs/lockd/clntproc.c 2003-06-15 14:47:37.000000000 -0700 @@ -460,7 +460,7 @@ } if (status < 0) return status; - } while (resp->status == NLM_LCK_BLOCKED); + } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block); if (resp->status == NLM_LCK_GRANTED) { fl->fl_u.nfs_fl.state = host->h_state; diff -u --recursive --new-file linux-2.4.21-acpi/fs/lockd/host.c linux-2.4.21-15-seekdir/fs/lockd/host.c --- linux-2.4.21-acpi/fs/lockd/host.c 2001-10-01 13:45:47.000000000 -0700 +++ linux-2.4.21-15-seekdir/fs/lockd/host.c 2003-06-15 14:49:35.000000000 -0700 @@ -187,15 +187,7 @@ host->h_nextrebind - jiffies); } } else { - uid_t saved_fsuid = current->fsuid; - kernel_cap_t saved_cap = current->cap_effective; - - /* Create RPC socket as root user so we get a priv port */ - current->fsuid = 0; - cap_raise (current->cap_effective, CAP_NET_BIND_SERVICE); xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL); - current->fsuid = saved_fsuid; - current->cap_effective = saved_cap; if (xprt == NULL) goto forgetit; @@ -209,6 +201,7 @@ } clnt->cl_autobind = 1; /* turn on pmap queries */ xprt->nocong = 1; /* No congestion control for NLM */ + xprt->resvport = 1; /* NLM requires a reserved port */ host->h_rpcclnt = clnt; } diff -u --recursive --new-file linux-2.4.21-acpi/fs/lockd/mon.c linux-2.4.21-15-seekdir/fs/lockd/mon.c --- linux-2.4.21-acpi/fs/lockd/mon.c 2001-10-01 13:45:47.000000000 -0700 +++ linux-2.4.21-15-seekdir/fs/lockd/mon.c 2003-06-15 14:49:35.000000000 -0700 @@ -122,6 +122,7 @@ clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clnt->cl_oneshot = 1; + xprt->resvport = 1; /* NSM requires a reserved port */ out: return clnt; diff -u --recursive --new-file linux-2.4.21-acpi/fs/lockd/svc4proc.c linux-2.4.21-15-seekdir/fs/lockd/svc4proc.c --- linux-2.4.21-acpi/fs/lockd/svc4proc.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.21-15-seekdir/fs/lockd/svc4proc.c 2003-06-15 14:47:59.000000000 -0700 @@ -462,6 +462,24 @@ } /* + * client sent a GRANTED_RES, let's remove the associated block + */ +static int +nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, + void *resp) +{ + if (!nlmsvc_ops) + return rpc_success; + + dprintk("lockd: GRANTED_RES called\n"); + + nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); + return rpc_success; +} + + + +/* * This is the generic lockd callback for async RPC calls */ static u32 @@ -524,7 +542,6 @@ #define nlm4svc_proc_lock_res nlm4svc_proc_null #define nlm4svc_proc_cancel_res nlm4svc_proc_null #define nlm4svc_proc_unlock_res nlm4svc_proc_null -#define nlm4svc_proc_granted_res nlm4svc_proc_null struct nlm_void { int dummy; }; @@ -559,7 +576,7 @@ PROC(lock_res, lockres, norep, res, void, 1), PROC(cancel_res, cancelres, norep, res, void, 1), PROC(unlock_res, unlockres, norep, res, void, 1), - PROC(granted_res, grantedres, norep, res, void, 1), + PROC(granted_res, res, norep, res, void, 1), /* statd callback */ PROC(sm_notify, reboot, void, reboot, void, 1), PROC(none, void, void, void, void, 0), diff -u --recursive --new-file linux-2.4.21-acpi/fs/lockd/svclock.c linux-2.4.21-15-seekdir/fs/lockd/svclock.c --- linux-2.4.21-acpi/fs/lockd/svclock.c 2001-10-11 07:52:18.000000000 -0700 +++ linux-2.4.21-15-seekdir/fs/lockd/svclock.c 2003-06-15 14:48:01.000000000 -0700 @@ -64,7 +64,7 @@ if (when != NLM_NEVER) { if ((when += jiffies) == NLM_NEVER) when ++; - while ((b = *bp) && time_before_eq(b->b_when,when)) + while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER) bp = &b->b_next; } else while ((b = *bp)) @@ -143,14 +143,15 @@ * Find a block with a given NLM cookie. */ static inline struct nlm_block * -nlmsvc_find_block(struct nlm_cookie *cookie) +nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin) { struct nlm_block *block; for (block = nlm_blocked; block; block = block->b_next) { dprintk("cookie: head of blocked queue %p, block %p\n", nlm_blocked, block); - if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie)) + if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie) + && nlm_cmp_addr(sin, &block->b_host->h_addr)) break; } @@ -572,12 +573,16 @@ struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; struct nlm_block *block; unsigned long timeout; + struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client); dprintk("lockd: GRANT_MSG RPC callback\n"); - dprintk("callback: looking for cookie %x \n", - *(unsigned int *)(call->a_args.cookie.data)); - if (!(block = nlmsvc_find_block(&call->a_args.cookie))) { - dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data)); + dprintk("callback: looking for cookie %x, host (%08x)\n", + *(unsigned int *)(call->a_args.cookie.data), + ntohl(peer_addr->sin_addr.s_addr)); + if (!(block = nlmsvc_find_block(&call->a_args.cookie, peer_addr))) { + dprintk("lockd: no block for cookie %x, host (%08x)\n", + *(u32 *)(call->a_args.cookie.data), + ntohl(peer_addr->sin_addr.s_addr)); return; } @@ -606,18 +611,21 @@ * block. */ void -nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status) +nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status) { struct nlm_block *block; struct nlm_file *file; - if (!(block = nlmsvc_find_block(cookie))) + dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n", + *(unsigned int *)(cookie->data), + ntohl(rqstp->rq_addr.sin_addr.s_addr), status); + if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr))) return; file = block->b_file; file->f_count++; down(&file->f_sema); - if ((block = nlmsvc_find_block(cookie)) != NULL) { + if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) { if (status == NLM_LCK_DENIED_GRACE_PERIOD) { /* Try again in a couple of seconds */ nlmsvc_insert_block(block, 10 * HZ); diff -u --recursive --new-file linux-2.4.21-acpi/fs/lockd/svcproc.c linux-2.4.21-15-seekdir/fs/lockd/svcproc.c --- linux-2.4.21-acpi/fs/lockd/svcproc.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.21-15-seekdir/fs/lockd/svcproc.c 2003-06-15 14:47:59.000000000 -0700 @@ -490,6 +490,22 @@ } /* + * client sent a GRANTED_RES, let's remove the associated block + */ +static int +nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, + void *resp) +{ + if (!nlmsvc_ops) + return rpc_success; + + dprintk("lockd: GRANTED_RES called\n"); + + nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); + return rpc_success; +} + +/* * This is the generic lockd callback for async RPC calls */ static u32 @@ -552,7 +568,6 @@ #define nlmsvc_proc_lock_res nlmsvc_proc_null #define nlmsvc_proc_cancel_res nlmsvc_proc_null #define nlmsvc_proc_unlock_res nlmsvc_proc_null -#define nlmsvc_proc_granted_res nlmsvc_proc_null struct nlm_void { int dummy; }; @@ -589,7 +604,7 @@ PROC(lock_res, lockres, norep, res, void, 1), PROC(cancel_res, cancelres, norep, res, void, 1), PROC(unlock_res, unlockres, norep, res, void, 1), - PROC(granted_res, grantedres, norep, res, void, 1), + PROC(granted_res, res, norep, res, void, 1), /* statd callback */ PROC(sm_notify, reboot, void, reboot, void, 1), PROC(none, void, void, void, void, 1), diff -u --recursive --new-file linux-2.4.21-acpi/fs/nfs/dir.c linux-2.4.21-15-seekdir/fs/nfs/dir.c --- linux-2.4.21-acpi/fs/nfs/dir.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.21-15-seekdir/fs/nfs/dir.c 2003-06-15 14:58:09.000000000 -0700 @@ -34,6 +34,7 @@ #define NFS_PARANOIA 1 /* #define NFS_DEBUG_VERBOSE 1 */ +static loff_t nfs_dir_llseek(struct file *, loff_t, int); static int nfs_readdir(struct file *, void *, filldir_t); static struct dentry *nfs_lookup(struct inode *, struct dentry *); static int nfs_create(struct inode *, struct dentry *, int); @@ -48,6 +49,7 @@ static int nfs_fsync_dir(struct file *, struct dentry *, int); struct file_operations nfs_dir_operations = { + llseek: nfs_dir_llseek, read: generic_read_dir, readdir: nfs_readdir, open: nfs_open, @@ -70,6 +72,25 @@ setattr: nfs_notify_change, }; +static loff_t nfs_dir_llseek(struct file *file, loff_t offset, int origin) +{ + switch (origin) { + case 1: + if (offset == 0) { + offset = file->f_pos; + break; + } + case 2: + return -EINVAL; + } + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; + } + return (offset <= 0) ? 0 : offset; +} + typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int); typedef struct { struct file *file; @@ -994,7 +1015,7 @@ struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct dentry *dentry = NULL, *rehash = NULL; - int error = -EBUSY; + int error; /* * To prevent any new references to the target during the rename, @@ -1020,6 +1041,12 @@ */ if (!new_inode) goto go_ahead; + /* If target is a hard link to the source, then noop */ + error = 0; + if (NFS_FILEID(new_inode) == NFS_FILEID(old_inode)) + goto out; + + error = -EBUSY; if (S_ISDIR(new_inode->i_mode)) goto out; else if (atomic_read(&new_dentry->d_count) > 1) { diff -u --recursive --new-file linux-2.4.21-acpi/fs/nfs/nfs2xdr.c linux-2.4.21-15-seekdir/fs/nfs/nfs2xdr.c --- linux-2.4.21-acpi/fs/nfs/nfs2xdr.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.21-15-seekdir/fs/nfs/nfs2xdr.c 2003-06-15 14:58:09.000000000 -0700 @@ -369,7 +369,7 @@ count = count >> 2; p = xdr_encode_fhandle(p, args->fh); - *p++ = htonl(args->cookie); + *p++ = htonl(args->cookie & 0xFFFFFFFF); *p++ = htonl(count); /* see above */ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); @@ -466,7 +466,7 @@ entry->name = (const char *) p; p += XDR_QUADLEN(entry->len); entry->prev_cookie = entry->cookie; - entry->cookie = ntohl(*p++); + entry->cookie = (s64)((off_t)ntohl(*p++)); entry->eof = !p[0] && p[1]; return p; diff -u --recursive --new-file linux-2.4.21-acpi/fs/nfs/nfs3proc.c linux-2.4.21-15-seekdir/fs/nfs/nfs3proc.c --- linux-2.4.21-acpi/fs/nfs/nfs3proc.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.21-15-seekdir/fs/nfs/nfs3proc.c 2003-06-15 14:49:36.000000000 -0700 @@ -298,16 +298,21 @@ static int nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) { + struct { + struct nfs3_diropargs arg; + struct nfs_fattr res; + } *data; struct nfs3_diropargs *arg; struct nfs_fattr *res; - arg = (struct nfs3_diropargs *)kmalloc(sizeof(*arg)+sizeof(*res), GFP_KERNEL); - if (!arg) + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) return -ENOMEM; - res = (struct nfs_fattr*)(arg + 1); + arg = &data->arg; arg->fh = NFS_FH(dir->d_inode); arg->name = name->name; arg->len = name->len; + res = &data->res; res->valid = 0; msg->rpc_proc = NFS3PROC_REMOVE; msg->rpc_argp = arg; diff -u --recursive --new-file linux-2.4.21-acpi/fs/nfs/nfs3xdr.c linux-2.4.21-15-seekdir/fs/nfs/nfs3xdr.c --- linux-2.4.21-acpi/fs/nfs/nfs3xdr.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.21-15-seekdir/fs/nfs/nfs3xdr.c 2003-06-15 14:58:09.000000000 -0700 @@ -465,6 +465,13 @@ return 0; } +/* Hack to sign-extending 32-bit cookies */ +static inline +u64 nfs_transform_cookie64(u64 cookie) +{ + return (cookie & 0x80000000) ? (cookie ^ 0xFFFFFFFF00000000) : cookie; +} + /* * Encode arguments to readdir call */ @@ -476,7 +483,7 @@ u32 count = args->count; p = xdr_encode_fhandle(p, args->fh); - p = xdr_encode_hyper(p, args->cookie); + p = xdr_encode_hyper(p, nfs_transform_cookie64(args->cookie)); *p++ = args->verf[0]; *p++ = args->verf[1]; if (args->plus) { @@ -600,6 +607,7 @@ nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) { struct nfs_entry old = *entry; + u64 cookie; if (!*p++) { if (!*p) @@ -613,7 +621,8 @@ entry->name = (const char *) p; p += XDR_QUADLEN(entry->len); entry->prev_cookie = entry->cookie; - p = xdr_decode_hyper(p, &entry->cookie); + p = xdr_decode_hyper(p, &cookie); + entry->cookie = nfs_transform_cookie64(cookie); if (plus) { p = xdr_decode_post_op_attr(p, &entry->fattr); diff -u --recursive --new-file linux-2.4.21-acpi/fs/nfs/unlink.c linux-2.4.21-15-seekdir/fs/nfs/unlink.c --- linux-2.4.21-acpi/fs/nfs/unlink.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.21-15-seekdir/fs/nfs/unlink.c 2003-06-15 14:49:36.000000000 -0700 @@ -12,6 +12,7 @@ #include #include #include +#include struct nfs_unlinkdata { @@ -21,6 +22,9 @@ struct rpc_task task; struct rpc_cred *cred; unsigned int count; + + wait_queue_head_t waitq; + int completed; }; static struct nfs_unlinkdata *nfs_deletes; @@ -133,6 +137,8 @@ put_rpccred(data->cred); data->cred = NULL; dput(dir); + data->completed = 1; + wake_up(&data->waitq); } /** @@ -175,6 +181,8 @@ nfs_deletes = data; data->count = 1; + init_waitqueue_head(&data->waitq); + task = &data->task; rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC); task->tk_calldata = data; @@ -212,7 +220,10 @@ data->count++; nfs_copy_dname(dentry, data); dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; - if (data->task.tk_rpcwait == &nfs_delete_queue) + if (data->task.tk_rpcwait == &nfs_delete_queue) { + struct rpc_clnt *clnt = data->task.tk_client; rpc_wake_up_task(&data->task); + nfs_wait_event(clnt, data->waitq, data->completed == 1); + } nfs_put_unlinkdata(data); } diff -u --recursive --new-file linux-2.4.21-acpi/fs/nfs/write.c linux-2.4.21-15-seekdir/fs/nfs/write.c --- linux-2.4.21-acpi/fs/nfs/write.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.21-15-seekdir/fs/nfs/write.c 2003-06-15 14:47:14.000000000 -0700 @@ -812,8 +812,15 @@ * If wsize is smaller than page size, update and write * page synchronously. */ - if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE || IS_SYNC(inode)) - return nfs_writepage_sync(file, inode, page, offset, count); + if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE || IS_SYNC(inode)) { + status = nfs_writepage_sync(file, inode, page, offset, count); + if (status > 0) { + if (offset == 0 && status == PAGE_CACHE_SIZE) + SetPageUptodate(page); + return 0; + } + return status; + } /* * Try to find an NFS request corresponding to this page diff -u --recursive --new-file linux-2.4.21-acpi/include/linux/lockd/lockd.h linux-2.4.21-15-seekdir/include/linux/lockd/lockd.h --- linux-2.4.21-acpi/include/linux/lockd/lockd.h 2001-11-22 11:47:20.000000000 -0800 +++ linux-2.4.21-15-seekdir/include/linux/lockd/lockd.h 2003-06-15 14:47:59.000000000 -0700 @@ -164,6 +164,7 @@ unsigned long nlmsvc_retry_blocked(void); int nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, int action); +void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32); /* * File handling for the server personality diff -u --recursive --new-file linux-2.4.21-acpi/include/linux/sunrpc/xprt.h linux-2.4.21-15-seekdir/include/linux/sunrpc/xprt.h --- linux-2.4.21-acpi/include/linux/sunrpc/xprt.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.21-15-seekdir/include/linux/sunrpc/xprt.h 2003-06-15 14:49:35.000000000 -0700 @@ -44,6 +44,19 @@ #define RPC_MAX_UDP_TIMEOUT (60*HZ) #define RPC_MAX_TCP_TIMEOUT (600*HZ) +/* + * * Wait duration for an RPC TCP connection to be established. Solaris + * * NFS over TCP uses 60 seconds, for example, which is in line with how + * * long a server takes to reboot. + * */ +#define RPC_CONNECT_TIMEOUT (60*HZ) + +/* + * * Delay an arbitrary number of seconds before attempting to reconnect + * * after an error. + * */ +#define RPC_REESTABLISH_TIMEOUT (15*HZ) + /* RPC call and reply header size as number of 32bit words (verifier * size computed separately) */ @@ -57,8 +70,7 @@ unsigned long to_current, /* current timeout */ to_initval, /* initial timeout */ to_maxval, /* max timeout */ - to_increment, /* if !exponential */ - to_resrvval; /* reserve timeout */ + to_increment; /* if !exponential */ short to_retries; /* max # of retries */ unsigned char to_exponential; }; @@ -134,6 +146,7 @@ unsigned long sockstate; /* Socket state */ unsigned char shutdown : 1, /* being shut down */ nocong : 1, /* no congestion control */ + resvport : 1, /* use a reserved port */ stream : 1; /* TCP */ /* @@ -173,18 +186,18 @@ void xprt_set_timeout(struct rpc_timeout *, unsigned int, unsigned long); -int xprt_reserve(struct rpc_task *); +void xprt_reserve(struct rpc_task *); void xprt_transmit(struct rpc_task *); void xprt_receive(struct rpc_task *); int xprt_adjust_timeout(struct rpc_timeout *); void xprt_release(struct rpc_task *); -void xprt_reconnect(struct rpc_task *); +void xprt_connect(struct rpc_task *); int xprt_clear_backlog(struct rpc_xprt *); void xprt_sock_setbufsize(struct rpc_xprt *); #define XPRT_CONNECT 0 -#define xprt_connected(xp) (!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_connected(xp) (test_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_test_and_set_connected(xp) (test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_clear_connected(xp) (clear_bit(XPRT_CONNECT, &(xp)->sockstate)) diff -u --recursive --new-file linux-2.4.21-acpi/net/sunrpc/clnt.c linux-2.4.21-15-seekdir/net/sunrpc/clnt.c --- linux-2.4.21-acpi/net/sunrpc/clnt.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.21-15-seekdir/net/sunrpc/clnt.c 2003-06-15 14:49:35.000000000 -0700 @@ -55,9 +55,8 @@ static void call_refresh(struct rpc_task *task); static void call_refreshresult(struct rpc_task *task); static void call_timeout(struct rpc_task *task); -static void call_reconnect(struct rpc_task *task); -static void child_reconnect(struct rpc_task *); -static void child_reconnect_status(struct rpc_task *); +static void call_connect(struct rpc_task *task); +static void call_connect_status(struct rpc_task *); static u32 * call_header(struct rpc_task *task); static u32 * call_verify(struct rpc_task *task); @@ -394,8 +393,6 @@ static void call_reserve(struct rpc_task *task) { - struct rpc_clnt *clnt = task->tk_client; - dprintk("RPC: %4d call_reserve\n", task->tk_pid); if (!rpcauth_uptodatecred(task)) { @@ -405,7 +402,6 @@ task->tk_status = 0; task->tk_action = call_reserveresult; - task->tk_timeout = clnt->cl_timeout.to_resrvval; xprt_reserve(task); } @@ -419,38 +415,46 @@ dprintk("RPC: %4d call_reserveresult (status %d)\n", task->tk_pid, task->tk_status); + /* * After a call to xprt_reserve(), we must have either * a request slot or else an error status. */ - if ((task->tk_status >= 0 && !task->tk_rqstp) || - (task->tk_status < 0 && task->tk_rqstp)) - printk(KERN_ERR "call_reserveresult: status=%d, request=%p??\n", - task->tk_status, task->tk_rqstp); + task->tk_status = 0; + if (status >= 0) { + if (task->tk_rqstp) { + task->tk_action = call_allocate; + return; + } - if (task->tk_status >= 0) { - task->tk_action = call_allocate; + printk(KERN_ERR "%s: status=%d, but no request slot, exiting\n", + __FUNCTION__, status); + rpc_exit(task, -EIO); return; } - task->tk_status = 0; + /* + * Even though there was an error, we may have acquired + * a request slot somehow. Make sure not to leak it. + */ + if (task->tk_rqstp) { + printk(KERN_ERR "%s: status=%d, request allocated anyway\n", + __FUNCTION__, status); + xprt_release(task); + } + switch (status) { - case -EAGAIN: - case -ENOBUFS: - task->tk_timeout = task->tk_client->cl_timeout.to_resrvval; + case -EAGAIN: /* woken up; retry */ task->tk_action = call_reserve; - break; - case -ETIMEDOUT: - dprintk("RPC: task timed out\n"); - task->tk_action = call_timeout; + return; + case -EIO: /* probably a shutdown */ break; default: - if (!task->tk_rqstp) { - printk(KERN_INFO "RPC: task has no request, exit EIO\n"); - rpc_exit(task, -EIO); - } else - rpc_exit(task, status); + printk(KERN_ERR "%s: unrecognized error %d, exiting\n", + __FUNCTION__, status); + break; } + rpc_exit(task, status); } /* @@ -545,53 +549,69 @@ struct rpc_clnt *clnt = task->tk_client; struct rpc_xprt *xprt = clnt->cl_xprt; - task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_reconnect; + dprintk("RPC: %4d call_bind xprt %p %s connected\n", task->tk_pid, + xprt, (xprt_connected(xprt) ? "is" : "is not")); + + task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_connect; if (!clnt->cl_port) { - task->tk_action = call_reconnect; + task->tk_action = call_connect; task->tk_timeout = clnt->cl_timeout.to_maxval; rpc_getport(task, clnt); } } /* - * 4a. Reconnect to the RPC server (TCP case) + * 4a. Establish socket + * Connect to the RPC server (TCP case) */ static void -call_reconnect(struct rpc_task *task) +call_connect(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - struct rpc_task *child; - dprintk("RPC: %4d call_reconnect status %d\n", + dprintk("RPC: %4d call_connect status %d\n", task->tk_pid, task->tk_status); - task->tk_action = call_transmit; - if (task->tk_status < 0 || !clnt->cl_xprt->stream) + if (xprt_connected(clnt->cl_xprt)) { + task->tk_action = call_transmit; return; - - /* Run as a child to ensure it runs as an rpciod task */ - child = rpc_new_child(clnt, task); - if (child) { - child->tk_action = child_reconnect; - rpc_run_child(task, child, NULL); } + task->tk_action = call_connect_status; + if (task->tk_status < 0) + return; + xprt_connect(task); } -static void child_reconnect(struct rpc_task *task) +/* + * 4b. Sort out reconnection result + */ +static void call_connect_status(struct rpc_task *task) { - task->tk_client->cl_stats->netreconn++; + struct rpc_clnt *clnt = task->tk_client; + int status = task->tk_status; + task->tk_status = 0; - task->tk_action = child_reconnect_status; - xprt_reconnect(task); -} + if (status >= 0) { + clnt->cl_stats->netreconn++; + task->tk_action = call_transmit; + return; + } -static void child_reconnect_status(struct rpc_task *task) -{ - if (task->tk_status == -EAGAIN) - task->tk_action = child_reconnect; - else - task->tk_action = NULL; + /* Something failed: we may have to rebind */ + if (clnt->cl_autobind) + clnt->cl_port = 0; + switch (status) { + case -ECONNREFUSED: + case -ECONNRESET: + case -ENOTCONN: + case -ETIMEDOUT: + case -EAGAIN: + task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect; + break; + default: + rpc_exit(task, status); + } } /* @@ -651,10 +671,8 @@ task->tk_action = call_bind; break; } - if (xprt->stream) { - task->tk_action = call_reconnect; - break; - } + task->tk_action = call_connect; + break; /* * Sleep and dream of an open connection */ @@ -681,20 +699,15 @@ call_timeout(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - struct rpc_rqst *req = task->tk_rqstp; - - if (req) { - struct rpc_timeout *to = &req->rq_timeout; + struct rpc_timeout *to = &task->tk_rqstp->rq_timeout; - if (xprt_adjust_timeout(to)) { - dprintk("RPC: %4d call_timeout (minor timeo)\n", - task->tk_pid); - goto minor_timeout; - } - to->to_retries = clnt->cl_timeout.to_retries; + if (xprt_adjust_timeout(to)) { + dprintk("RPC: %4d call_timeout (minor)\n", task->tk_pid); + goto retry; } + to->to_retries = clnt->cl_timeout.to_retries; - dprintk("RPC: %4d call_timeout (major timeo)\n", task->tk_pid); + dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid); if (clnt->cl_softrtry) { if (clnt->cl_chatty && !task->tk_exit) printk(KERN_NOTICE "%s: server %s not responding, timed out\n", @@ -702,33 +715,18 @@ rpc_exit(task, -EIO); return; } + if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN) && rpc_ntimeo(&clnt->cl_rtt) > 7) { task->tk_flags |= RPC_CALL_MAJORSEEN; - if (req) - printk(KERN_NOTICE "%s: server %s not responding, still trying\n", - clnt->cl_protname, clnt->cl_server); -#ifdef RPC_DEBUG - else - printk(KERN_NOTICE "%s: task %d can't get a request slot\n", - clnt->cl_protname, task->tk_pid); -#endif + printk(KERN_NOTICE "%s: server %s not responding, still trying\n", + clnt->cl_protname, clnt->cl_server); } if (clnt->cl_autobind) clnt->cl_port = 0; -minor_timeout: - if (!req) - task->tk_action = call_reserve; - else if (!clnt->cl_port) { - task->tk_action = call_bind; - clnt->cl_stats->rpcretrans++; - } else if (!xprt_connected(clnt->cl_xprt)) { - task->tk_action = call_reconnect; - clnt->cl_stats->rpcretrans++; - } else { - task->tk_action = call_transmit; - clnt->cl_stats->rpcretrans++; - } +retry: + clnt->cl_stats->rpcretrans++; + task->tk_action = call_bind; task->tk_status = 0; } diff -u --recursive --new-file linux-2.4.21-acpi/net/sunrpc/xprt.c linux-2.4.21-15-seekdir/net/sunrpc/xprt.c --- linux-2.4.21-acpi/net/sunrpc/xprt.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.21-15-seekdir/net/sunrpc/xprt.c 2003-06-15 15:14:14.000000000 -0700 @@ -83,10 +83,10 @@ */ static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); static void do_xprt_transmit(struct rpc_task *); -static void xprt_reserve_status(struct rpc_task *task); +static inline void do_xprt_reserve(struct rpc_task *); static void xprt_disconnect(struct rpc_xprt *); -static void xprt_reconn_status(struct rpc_task *task); -static struct socket *xprt_create_socket(int, struct rpc_timeout *); +static void xprt_connect_status(struct rpc_task *task); +static struct socket *xprt_create_socket(int, struct rpc_timeout *, int); static int xprt_bind_socket(struct rpc_xprt *, struct socket *); static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); @@ -133,14 +133,17 @@ /* * Serialize write access to sockets, in order to prevent different * requests from interfering with each other. - * Also prevents TCP socket reconnections from colliding with writes. + * Also prevents TCP socket connections from colliding with writes. */ static int __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) { if (!xprt->snd_task) { - if (xprt->nocong || __xprt_get_cong(xprt, task)) + if (xprt->nocong || __xprt_get_cong(xprt, task)) { xprt->snd_task = task; + if (task->tk_rqstp) + task->tk_rqstp->rq_bytes_sent = 0; + } } if (xprt->snd_task != task) { dprintk("RPC: %4d TCP write queue full\n", task->tk_pid); @@ -179,8 +182,11 @@ if (!task) return; } - if (xprt->nocong || __xprt_get_cong(xprt, task)) + if (xprt->nocong || __xprt_get_cong(xprt, task)) { xprt->snd_task = task; + if (task->tk_rqstp) + task->tk_rqstp->rq_bytes_sent = 0; + } } /* @@ -266,6 +272,7 @@ */ case -EAGAIN: break; + case -ECONNRESET: case -ENOTCONN: case -EPIPE: /* connection broken */ @@ -383,6 +390,7 @@ if (!sk) return; + write_lock_bh(&sk->callback_lock); xprt->inet = NULL; xprt->sock = NULL; @@ -390,17 +398,12 @@ sk->data_ready = xprt->old_data_ready; sk->state_change = xprt->old_state_change; sk->write_space = xprt->old_write_space; + write_unlock_bh(&sk->callback_lock); xprt_disconnect(xprt); sk->no_check = 0; sock_release(sock); - /* - * TCP doesn't require the rpciod now - other things may - * but rpciod handles that not us. - */ - if(xprt->stream) - rpciod_down(); } /* @@ -410,31 +413,29 @@ xprt_disconnect(struct rpc_xprt *xprt) { dprintk("RPC: disconnected transport %p\n", xprt); + spin_lock_bh(&xprt->sock_lock); xprt_clear_connected(xprt); rpc_wake_up_status(&xprt->pending, -ENOTCONN); + spin_unlock_bh(&xprt->sock_lock); } /* * Reconnect a broken TCP connection. * - * Note: This cannot collide with the TCP reads, as both run from rpciod */ void -xprt_reconnect(struct rpc_task *task) +xprt_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; struct socket *sock = xprt->sock; struct sock *inet; int status; - dprintk("RPC: %4d xprt_reconnect %p connected %d\n", + dprintk("RPC: %4d xprt_connect %p connected %d\n", task->tk_pid, xprt, xprt_connected(xprt)); if (xprt->shutdown) return; - if (!xprt->stream) - return; - if (!xprt->addr.sin_port) { task->tk_status = -EIO; return; @@ -445,76 +446,112 @@ if (xprt_connected(xprt)) goto out_write; - if (sock && sock->state != SS_UNCONNECTED) - xprt_close(xprt); - status = -ENOTCONN; - if (!(inet = xprt->inet)) { - /* Create an unconnected socket */ - if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout))) - goto defer; - xprt_bind_socket(xprt, sock); - inet = sock->sk; + if (task->tk_rqstp) + task->tk_rqstp->rq_bytes_sent = 0; + + xprt_close(xprt); + /* Create an unconnected socket */ + sock = xprt_create_socket(xprt->prot, &xprt->timeout, xprt->resvport); + if (!sock) { + /* couldn't create socket or bind to reserved port; + * this is likely a permanent error, so cause an abort */ + task->tk_status = -EIO; + goto out_write; } + xprt_bind_socket(xprt, sock); + + if (!xprt->stream) + goto out_write; + + inet = sock->sk; /* Now connect it asynchronously. */ dprintk("RPC: %4d connecting new socket\n", task->tk_pid); status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, sizeof(xprt->addr), O_NONBLOCK); + dprintk("RPC: %4d connect status %d connected %d\n", + task->tk_pid, status, xprt_connected(xprt)); - if (status < 0) { - switch (status) { - case -EALREADY: - case -EINPROGRESS: - status = 0; - break; - case -EISCONN: - case -EPIPE: - status = 0; - xprt_close(xprt); - goto defer; - default: - printk("RPC: TCP connect error %d!\n", -status); - xprt_close(xprt); - goto defer; - } + if (status >= 0) + return; + switch (status) { + case -EALREADY: + case -EINPROGRESS: /* Protect against TCP socket state changes */ lock_sock(inet); - dprintk("RPC: %4d connect status %d connected %d\n", - task->tk_pid, status, xprt_connected(xprt)); - if (inet->state != TCP_ESTABLISHED) { - task->tk_timeout = xprt->timeout.to_maxval; - /* if the socket is already closing, delay 5 secs */ + dprintk("RPC: %4d waiting for connection\n", + task->tk_pid); + task->tk_timeout = RPC_CONNECT_TIMEOUT; + /* if the socket is already closing, delay briefly */ if ((1<state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV)) - task->tk_timeout = 5*HZ; - rpc_sleep_on(&xprt->pending, task, xprt_reconn_status, NULL); - release_sock(inet); - return; + task->tk_timeout = RPC_REESTABLISH_TIMEOUT; + rpc_sleep_on(&xprt->pending, task, xprt_connect_status, + NULL); } release_sock(inet); + break; + case -ECONNREFUSED: + case -ECONNRESET: + case -ENOTCONN: + if (!task->tk_client->cl_softrtry) { + rpc_delay(task, RPC_REESTABLISH_TIMEOUT); + task->tk_status = -ENOTCONN; + break; + } + default: + /* Report myriad other possible returns. If this file + * system is soft mounted, just error out, like Solaris. */ + if (task->tk_client->cl_softrtry) { + printk(KERN_WARNING + "RPC: error %d connecting to server %s, exiting\n", + -status, task->tk_client->cl_server); + task->tk_status = -EIO; + goto out_write; + } + printk(KERN_WARNING "RPC: error %d connecting to server %s\n", + -status, task->tk_client->cl_server); + /* This will prevent anybody else from connecting */ + rpc_delay(task, RPC_REESTABLISH_TIMEOUT); + task->tk_status = status; + break; } -defer: - if (status < 0) { - rpc_delay(task, 5*HZ); - task->tk_status = -ENOTCONN; - } + return; out_write: xprt_release_write(xprt, task); } /* - * Reconnect timeout. We just mark the transport as not being in the - * process of reconnecting, and leave the rest to the upper layers. + * We arrive here when awoken from waiting on connection establishment. */ static void -xprt_reconn_status(struct rpc_task *task) +xprt_connect_status(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - dprintk("RPC: %4d xprt_reconn_timeout %d\n", - task->tk_pid, task->tk_status); + if (task->tk_status >= 0) { + dprintk("RPC: %4d xprt_connect_status: connection established\n", + task->tk_pid); + return; + } + + /* if soft mounted, cause this RPC to fail */ + if (task->tk_client->cl_softrtry) + task->tk_status = -EIO; + switch (task->tk_status) { + case -ENOTCONN: + rpc_delay(task, RPC_REESTABLISH_TIMEOUT); + return; + case -ETIMEDOUT: + dprintk("RPC: %4d xprt_connect_status: timed out\n", + task->tk_pid); + break; + default: + printk(KERN_ERR "RPC: error %d connecting to server %s\n", + -task->tk_status, task->tk_client->cl_server); + } xprt_release_write(xprt, task); } @@ -657,8 +694,9 @@ struct sk_buff *skb; int err, repsize, copied; + read_lock(&sk->callback_lock); dprintk("RPC: udp_data_ready...\n"); - if (!(xprt = xprt_from_sock(sk))) { + if (sk->dead || !(xprt = xprt_from_sock(sk))) { printk("RPC: udp_data_ready request not found!\n"); goto out; } @@ -707,6 +745,7 @@ out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); + read_unlock(&sk->callback_lock); } /* @@ -895,7 +934,7 @@ } /* Skip over any trailing bytes on short reads */ tcp_read_discard(xprt, &desc); - } while (desc.count && xprt_connected(xprt)); + } while (desc.count); dprintk("RPC: tcp_data_recv done\n"); return len - desc.count; } @@ -905,18 +944,21 @@ struct rpc_xprt *xprt; read_descriptor_t rd_desc; + read_lock(&sk->callback_lock); dprintk("RPC: tcp_data_ready...\n"); if (!(xprt = xprt_from_sock(sk))) { printk("RPC: tcp_data_ready socket info not found!\n"); - return; + goto out; } if (xprt->shutdown) - return; + goto out; /* We use rd_desc to pass struct xprt to tcp_data_recv */ rd_desc.buf = (char *)xprt; rd_desc.count = 65536; tcp_read_sock(sk, &rd_desc, tcp_data_recv); +out: + read_unlock(&sk->callback_lock); } static void @@ -924,6 +966,7 @@ { struct rpc_xprt *xprt; + read_lock(&sk->callback_lock); if (!(xprt = xprt_from_sock(sk))) goto out; dprintk("RPC: tcp_state_change client %p...\n", xprt); @@ -942,10 +985,10 @@ xprt->tcp_copied = 0; xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; - spin_lock(&xprt->sock_lock); + spin_lock_bh(&xprt->sock_lock); if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) rpc_wake_up_task(xprt->snd_task); - spin_unlock(&xprt->sock_lock); + spin_unlock_bh(&xprt->sock_lock); break; case TCP_SYN_SENT: case TCP_SYN_RECV: @@ -957,6 +1000,7 @@ out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible_all(sk->sleep); + read_unlock(&sk->callback_lock); } /* @@ -971,24 +1015,25 @@ struct rpc_xprt *xprt; struct socket *sock; + read_lock(&sk->callback_lock); if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->socket)) - return; + goto out; if (xprt->shutdown) - return; + goto out; /* Wait until we have enough socket memory */ if (xprt->stream) { /* from net/ipv4/tcp.c:tcp_write_space */ if (tcp_wspace(sk) < tcp_min_write_space(sk)) - return; + goto out; } else { /* from net/core/sock.c:sock_def_write_space */ if (!sock_writeable(sk)) - return; + goto out; } if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)) - return; + goto out; spin_lock_bh(&xprt->sock_lock); if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) @@ -996,6 +1041,8 @@ spin_unlock_bh(&xprt->sock_lock); if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); +out: + read_unlock(&sk->callback_lock); } /* @@ -1063,9 +1110,6 @@ if (xprt->shutdown) task->tk_status = -EIO; - if (!xprt_connected(xprt)) - task->tk_status = -ENOTCONN; - if (task->tk_status < 0) return; @@ -1081,10 +1125,14 @@ } spin_lock_bh(&xprt->sock_lock); - if (!__xprt_lock_write(xprt, task)) { - spin_unlock_bh(&xprt->sock_lock); - return; + if (!__xprt_lock_write(xprt, task)) + goto out_notrans; + + if (!xprt_connected(xprt)) { + task->tk_status = -ENOTCONN; + goto out_notrans; } + if (list_empty(&req->rq_list)) { list_add_tail(&req->rq_list, &xprt->recv); req->rq_received = 0; @@ -1092,6 +1140,9 @@ spin_unlock_bh(&xprt->sock_lock); do_xprt_transmit(task); + return; +out_notrans: + spin_unlock_bh(&xprt->sock_lock); } static void @@ -1135,11 +1186,12 @@ break; } - /* Note: at this point, task->tk_sleeping has not yet been set, - * hence there is no danger of the waking up task being put on - * schedq, and being picked up by a parallel run of rpciod(). + /* If we're doing a resend and have received a reply already, + * then exit early. + * Note, though, that we can't do this if we've already started + * resending down a TCP stream. */ - if (req->rq_received) + if (req->rq_received && !req->rq_bytes_sent) goto out_release; task->tk_status = status; @@ -1149,7 +1201,10 @@ if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { /* Protect against races with xprt_write_space */ spin_lock_bh(&xprt->sock_lock); - if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { + /* Don't race with disconnect */ + if (!xprt_connected(xprt)) + task->tk_status = -ENOTCONN; + else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { task->tk_timeout = req->rq_timeout.to_current; rpc_sleep_on(&xprt->pending, task, NULL, NULL); } @@ -1160,13 +1215,13 @@ rpc_delay(task, HZ>>4); return; case -ECONNREFUSED: + task->tk_timeout = RPC_REESTABLISH_TIMEOUT; + rpc_sleep_on(&xprt->sending, task, NULL, NULL); case -ENOTCONN: - if (!xprt->stream) - return; + return; default: if (xprt->stream) xprt_disconnect(xprt); - req->rq_bytes_sent = 0; } out_release: xprt_release_write(xprt, task); @@ -1183,7 +1238,10 @@ } else task->tk_timeout = req->rq_timeout.to_current; spin_lock_bh(&xprt->sock_lock); - if (!req->rq_received) + /* Don't race with disconnect */ + if (!xprt_connected(xprt)) + task->tk_status = -ENOTCONN; + else if (!req->rq_received) rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); __xprt_release_write(xprt, task); spin_unlock_bh(&xprt->sock_lock); @@ -1192,61 +1250,39 @@ /* * Reserve an RPC call slot. */ -int +void xprt_reserve(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - /* We already have an initialized request. */ - if (task->tk_rqstp) - return 0; - - spin_lock(&xprt->xprt_lock); - xprt_reserve_status(task); - if (task->tk_rqstp) { - task->tk_timeout = 0; - } else if (!task->tk_timeout) { - task->tk_status = -ENOBUFS; - } else { - dprintk("RPC: xprt_reserve waiting on backlog\n"); - task->tk_status = -EAGAIN; - rpc_sleep_on(&xprt->backlog, task, NULL, NULL); + task->tk_status = -EIO; + if (!xprt->shutdown) { + spin_lock(&xprt->xprt_lock); + do_xprt_reserve(task); + spin_unlock(&xprt->xprt_lock); } - spin_unlock(&xprt->xprt_lock); - dprintk("RPC: %4d xprt_reserve returns %d\n", - task->tk_pid, task->tk_status); - return task->tk_status; } -/* - * Reservation callback - */ -static void -xprt_reserve_status(struct rpc_task *task) +static inline void +do_xprt_reserve(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - struct rpc_rqst *req; - if (xprt->shutdown) { - task->tk_status = -EIO; - } else if (task->tk_status < 0) { - /* NOP */ - } else if (task->tk_rqstp) { - /* We've already been given a request slot: NOP */ - } else { - if (!(req = xprt->free)) - goto out_nofree; - /* OK: There's room for us. Grab a free slot */ - xprt->free = req->rq_next; - req->rq_next = NULL; + task->tk_status = 0; + if (task->tk_rqstp) + return; + if (xprt->free) { + struct rpc_rqst *req = xprt->free; + xprt->free = req->rq_next; + req->rq_next = NULL; task->tk_rqstp = req; xprt_request_init(task, xprt); + return; } - - return; - -out_nofree: + dprintk("RPC: waiting for request slot\n"); task->tk_status = -EAGAIN; + task->tk_timeout = 0; + rpc_sleep_on(&xprt->backlog, task, NULL, NULL); } /* @@ -1339,7 +1375,6 @@ to->to_initval = to->to_increment = incr; to->to_maxval = incr * retr; - to->to_resrvval = incr * retr; to->to_retries = retr; to->to_exponential = 0; } @@ -1348,8 +1383,7 @@ * Initialize an RPC client */ static struct rpc_xprt * -xprt_setup(struct socket *sock, int proto, - struct sockaddr_in *ap, struct rpc_timeout *to) +xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) { struct rpc_xprt *xprt; struct rpc_rqst *req; @@ -1380,7 +1414,6 @@ if (to) { xprt->timeout = *to; xprt->timeout.to_current = to->to_initval; - xprt->timeout.to_resrvval = to->to_maxval << 1; } else xprt_default_timeout(&xprt->timeout, xprt->prot); @@ -1395,9 +1428,11 @@ req->rq_next = NULL; xprt->free = xprt->slot; + /* Check whether we want to use a reserved port */ + xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; + dprintk("RPC: created transport %p\n", xprt); - xprt_bind_socket(xprt, sock); return xprt; } @@ -1409,6 +1444,12 @@ { struct sockaddr_in myaddr; int err, port; + kernel_cap_t saved_cap = current->cap_effective; + + /* Override capabilities. + * They were checked in xprt_create_proto i.e. at mount time + */ + cap_raise (current->cap_effective, CAP_NET_BIND_SERVICE); memset(&myaddr, 0, sizeof(myaddr)); myaddr.sin_family = AF_INET; @@ -1418,6 +1459,7 @@ err = sock->ops->bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)); } while (err == -EADDRINUSE && --port > 0); + current->cap_effective = saved_cap; if (err < 0) printk("RPC: Can't bind to reserved port (%d).\n", -err); @@ -1433,6 +1475,7 @@ if (xprt->inet) return -EBUSY; + write_lock_bh(&sk->callback_lock); sk->user_data = xprt; xprt->old_data_ready = sk->data_ready; xprt->old_state_change = sk->state_change; @@ -1453,11 +1496,7 @@ /* Reset to new socket */ xprt->sock = sock; xprt->inet = sk; - /* - * TCP requires the rpc I/O daemon is present - */ - if(xprt->stream) - rpciod_up(); + write_unlock_bh(&sk->callback_lock); return 0; } @@ -1487,7 +1526,7 @@ * Create a client socket given the protocol and peer address. */ static struct socket * -xprt_create_socket(int proto, struct rpc_timeout *to) +xprt_create_socket(int proto, struct rpc_timeout *to, int resvport) { struct socket *sock; int type, err; @@ -1502,8 +1541,8 @@ goto failed; } - /* If the caller has the capability, bind to a reserved port */ - if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0) + /* bind to a reserved port */ + if (resvport && xprt_bindresvport(sock) < 0) goto failed; return sock; @@ -1519,18 +1558,19 @@ struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) { - struct socket *sock; struct rpc_xprt *xprt; - dprintk("RPC: xprt_create_proto called\n"); - - if (!(sock = xprt_create_socket(proto, to))) - return NULL; - - if (!(xprt = xprt_setup(sock, proto, sap, to))) - sock_release(sock); + xprt = xprt_setup(proto, sap, to); + if (!xprt) + goto out_bad; + dprintk("RPC: xprt_create_proto created xprt %p\n", xprt); return xprt; +out_bad: + dprintk("RPC: xprt_create_proto failed\n"); + if (xprt) + kfree(xprt); + return NULL; } /*