diff -u --recursive --new-file linux-2.4.19-fix_lockd4/Documentation/Configure.help linux-2.4.19-neilb/Documentation/Configure.help --- linux-2.4.19-fix_lockd4/Documentation/Configure.help Thu Aug 1 12:32:34 2002 +++ linux-2.4.19-neilb/Documentation/Configure.help Thu Aug 1 12:36:26 2002 @@ -14908,13 +14908,10 @@ If you would like to include the NFSv3 server as well as the NFSv2 server, say Y here. If unsure, say Y. -Provide NFS over TCP server support DEVELOPER ONLY +Provide NFS over TCP server support EXPERIMENTAL CONFIG_NFSD_TCP - If you are a developer and want to work on fixing problems with - NFS server over TCP support, say Y here. If unsure, say N. - - Some problems can be found by looking for FIXME in - . + Enable NFS service over TCP connections. This the officially + still experimental, but seems to work well. OS/2 HPFS file system support CONFIG_HPFS_FS diff -u --recursive --new-file linux-2.4.19-fix_lockd4/fs/Config.in linux-2.4.19-neilb/fs/Config.in --- linux-2.4.19-fix_lockd4/fs/Config.in Thu Aug 1 12:32:34 2002 +++ linux-2.4.19-neilb/fs/Config.in Thu Aug 1 12:36:26 2002 @@ -100,6 +100,7 @@ dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET dep_mbool ' Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD + dep_mbool ' Provide NFS server over TCP support (EXPERIMENTAL)' CONFIG_NFSD_TCP $CONFIG_NFSD $CONFIG_EXPERIMENTAL if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then define_tristate CONFIG_SUNRPC y diff -u --recursive --new-file linux-2.4.19-fix_lockd4/fs/lockd/svc4proc.c linux-2.4.19-neilb/fs/lockd/svc4proc.c --- linux-2.4.19-fix_lockd4/fs/lockd/svc4proc.c Thu Aug 1 12:35:30 2002 +++ linux-2.4.19-neilb/fs/lockd/svc4proc.c Thu Aug 1 12:36:26 2002 @@ -545,7 +545,7 @@ struct nlm_void { int dummy; }; -#define PROC(name, xargt, xrest, argt, rest) \ +#define PROC(name, xargt, xrest, argt, rest, respsize) \ { (svc_procfunc) nlm4svc_proc_##name, \ (kxdrproc_t) nlm4svc_decode_##xargt, \ (kxdrproc_t) nlm4svc_encode_##xrest, \ @@ -553,33 +553,34 @@ sizeof(struct nlm_##argt), \ sizeof(struct nlm_##rest), \ 0, \ - 0 \ + 0, \ + respsize, \ } struct svc_procedure nlmsvc_procedures4[] = { - PROC(null, void, void, void, void), - PROC(test, testargs, testres, args, res), - PROC(lock, lockargs, res, args, res), - PROC(cancel, cancargs, res, args, res), - PROC(unlock, unlockargs, res, args, res), - PROC(granted, testargs, res, args, res), - PROC(test_msg, testargs, norep, args, void), - PROC(lock_msg, lockargs, norep, args, void), - PROC(cancel_msg, cancargs, norep, args, void), - PROC(unlock_msg, unlockargs, norep, args, void), - PROC(granted_msg, testargs, norep, args, void), - PROC(test_res, testres, norep, res, void), - PROC(lock_res, lockres, norep, res, void), - PROC(cancel_res, cancelres, norep, res, void), - PROC(unlock_res, unlockres, norep, res, void), - PROC(granted_res, res, norep, res, void), + PROC(null, void, void, void, void, 0), + PROC(test, testargs, testres, args, res, 0), + PROC(lock, lockargs, res, args, res, 0), + PROC(cancel, cancargs, res, args, res, 0), + PROC(unlock, unlockargs, res, args, res, 0), + PROC(granted, testargs, res, args, res, 0), + PROC(test_msg, testargs, norep, args, void, 0), + PROC(lock_msg, lockargs, norep, args, void, 0), + PROC(cancel_msg, cancargs, norep, args, void, 0), + PROC(unlock_msg, unlockargs, norep, args, void, 0), + PROC(granted_msg, testargs, norep, args, void, 0), + PROC(test_res, testres, norep, res, void, 0), + PROC(lock_res, lockres, norep, res, void, 0), + PROC(cancel_res, cancelres, norep, res, void, 0), + PROC(unlock_res, unlockres, norep, res, void, 0), + PROC(granted_res, res, norep, res, void, 0), /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void), - PROC(none, void, void, void, void), - PROC(none, void, void, void, void), - PROC(none, void, void, void, void), - PROC(share, shareargs, shareres, args, res), - PROC(unshare, shareargs, shareres, args, res), - PROC(nm_lock, lockargs, res, args, res), - PROC(free_all, notify, void, args, void), + PROC(sm_notify, reboot, void, reboot, void, 0), + PROC(none, void, void, void, void, 0), + PROC(none, void, void, void, void, 0), + PROC(none, void, void, void, void, 0), + PROC(share, shareargs, shareres, args, res, 0), + PROC(unshare, shareargs, shareres, args, res, 0), + PROC(nm_lock, lockargs, res, args, res, 0), + PROC(free_all, notify, void, args, void, 0), }; diff -u --recursive --new-file linux-2.4.19-fix_lockd4/fs/lockd/svcproc.c linux-2.4.19-neilb/fs/lockd/svcproc.c --- linux-2.4.19-fix_lockd4/fs/lockd/svcproc.c Thu Aug 1 12:35:30 2002 +++ linux-2.4.19-neilb/fs/lockd/svcproc.c Thu Aug 1 12:36:26 2002 @@ -571,7 +571,7 @@ struct nlm_void { int dummy; }; -#define PROC(name, xargt, xrest, argt, rest) \ +#define PROC(name, xargt, xrest, argt, rest, respsize) \ { (svc_procfunc) nlmsvc_proc_##name, \ (kxdrproc_t) nlmsvc_decode_##xargt, \ (kxdrproc_t) nlmsvc_encode_##xrest, \ @@ -579,33 +579,34 @@ sizeof(struct nlm_##argt), \ sizeof(struct nlm_##rest), \ 0, \ - 0 \ + 0, \ + respsize, \ } struct svc_procedure nlmsvc_procedures[] = { - PROC(null, void, void, void, void), - PROC(test, testargs, testres, args, res), - PROC(lock, lockargs, res, args, res), - PROC(cancel, cancargs, res, args, res), - PROC(unlock, unlockargs, res, args, res), - PROC(granted, testargs, res, args, res), - PROC(test_msg, testargs, norep, args, void), - PROC(lock_msg, lockargs, norep, args, void), - PROC(cancel_msg, cancargs, norep, args, void), - PROC(unlock_msg, unlockargs, norep, args, void), - PROC(granted_msg, testargs, norep, args, void), - PROC(test_res, testres, norep, res, void), - PROC(lock_res, lockres, norep, res, void), - PROC(cancel_res, cancelres, norep, res, void), - PROC(unlock_res, unlockres, norep, res, void), - PROC(granted_res, res, norep, res, void), + PROC(null, void, void, void, void, 0), + PROC(test, testargs, testres, args, res, 0), + PROC(lock, lockargs, res, args, res, 0), + PROC(cancel, cancargs, res, args, res, 0), + PROC(unlock, unlockargs, res, args, res, 0), + PROC(granted, testargs, res, args, res, 0), + PROC(test_msg, testargs, norep, args, void, 0), + PROC(lock_msg, lockargs, norep, args, void, 0), + PROC(cancel_msg, cancargs, norep, args, void, 0), + PROC(unlock_msg, unlockargs, norep, args, void, 0), + PROC(granted_msg, testargs, norep, args, void, 0), + PROC(test_res, testres, norep, res, void, 0), + PROC(lock_res, lockres, norep, res, void, 0), + PROC(cancel_res, cancelres, norep, res, void, 0), + PROC(unlock_res, unlockres, norep, res, void, 0), + PROC(granted_res, res, norep, res, void, 0), /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void), - PROC(none, void, void, void, void), - PROC(none, void, void, void, void), - PROC(none, void, void, void, void), - PROC(share, shareargs, shareres, args, res), - PROC(unshare, shareargs, shareres, args, res), - PROC(nm_lock, lockargs, res, args, res), - PROC(free_all, notify, void, args, void), + PROC(sm_notify, reboot, void, reboot, void, 0), + PROC(none, void, void, void, void, 0), + PROC(none, void, void, void, void, 0), + PROC(none, void, void, void, void, 0), + PROC(share, shareargs, shareres, args, res, 0), + PROC(unshare, shareargs, shareres, args, res, 0), + PROC(nm_lock, lockargs, res, args, res, 0), + PROC(free_all, notify, void, args, void, 0), }; diff -u --recursive --new-file linux-2.4.19-fix_lockd4/fs/nfs/flushd.c linux-2.4.19-neilb/fs/nfs/flushd.c --- linux-2.4.19-fix_lockd4/fs/nfs/flushd.c Tue Mar 12 16:34:24 2002 +++ linux-2.4.19-neilb/fs/nfs/flushd.c Thu Aug 1 12:36:26 2002 @@ -50,7 +50,7 @@ /* * This is the wait queue all cluster daemons sleep on */ -static struct rpc_wait_queue flushd_queue = RPC_INIT_WAITQ("nfs_flushd"); +static RPC_WAITQ(flushd_queue, "nfs_flushd"); /* * Local function declarations. diff -u --recursive --new-file linux-2.4.19-fix_lockd4/fs/nfs/unlink.c linux-2.4.19-neilb/fs/nfs/unlink.c --- linux-2.4.19-fix_lockd4/fs/nfs/unlink.c Tue Feb 5 15:07:04 2002 +++ linux-2.4.19-neilb/fs/nfs/unlink.c Thu Aug 1 12:36:26 2002 @@ -24,7 +24,7 @@ }; static struct nfs_unlinkdata *nfs_deletes; -static struct rpc_wait_queue nfs_delete_queue = RPC_INIT_WAITQ("nfs_delete_queue"); +static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue"); /** * nfs_detach_unlinkdata - Remove asynchronous unlink from global list diff -u --recursive --new-file linux-2.4.19-fix_lockd4/fs/nfsd/nfs3proc.c linux-2.4.19-neilb/fs/nfsd/nfs3proc.c --- linux-2.4.19-fix_lockd4/fs/nfsd/nfs3proc.c Fri Apr 5 04:08:40 2002 +++ linux-2.4.19-neilb/fs/nfsd/nfs3proc.c Thu Aug 1 12:36:26 2002 @@ -183,11 +183,12 @@ */ svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail, 1 + NFS3_POST_OP_ATTR_WORDS + 3); - resp->count = argp->count; if ((avail << 2) < resp->count) resp->count = avail << 2; + svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + argp->count +4); + fh_copy(&resp->fh, &argp->fh); nfserr = nfsd_read(rqstp, &resp->fh, argp->offset, @@ -646,7 +647,7 @@ #define nfsd3_voidres nfsd3_voidargs struct nfsd3_voidargs { int dummy; }; -#define PROC(name, argt, rest, relt, cache) \ +#define PROC(name, argt, rest, relt, cache, respsize) \ { (svc_procfunc) nfsd3_proc_##name, \ (kxdrproc_t) nfs3svc_decode_##argt##args, \ (kxdrproc_t) nfs3svc_encode_##rest##res, \ @@ -654,29 +655,30 @@ sizeof(struct nfsd3_##argt##args), \ sizeof(struct nfsd3_##rest##res), \ 0, \ - cache \ + cache, \ + respsize, \ } struct svc_procedure nfsd_procedures3[22] = { - PROC(null, void, void, void, RC_NOCACHE), - PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE), - PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF), - PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE), - PROC(access, access, access, fhandle, RC_NOCACHE), - PROC(readlink, fhandle, readlink, fhandle, RC_NOCACHE), - PROC(read, read, read, fhandle, RC_NOCACHE), - PROC(write, write, write, fhandle, RC_REPLBUFF), - PROC(create, create, create, fhandle2, RC_REPLBUFF), - PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF), - PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF), - PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF), - PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF), - PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF), - PROC(rename, rename, rename, fhandle2, RC_REPLBUFF), - PROC(link, link, link, fhandle2, RC_REPLBUFF), - PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE), - PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE), - PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE), - PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE), - PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE), - PROC(commit, commit, commit, fhandle, RC_NOCACHE) + PROC(null, void, void, void, RC_NOCACHE, 1), + PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, 1+21), + PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF, 1+7+22), + PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, 1+9+22+22), + PROC(access, access, access, fhandle, RC_NOCACHE, 1+22+1), + PROC(readlink, fhandle, readlink, fhandle, RC_NOCACHE, 1+22+1+256), + PROC(read, read, read, fhandle, RC_NOCACHE, 1+22+4+NFSSVC_MAXBLKSIZE), + PROC(write, write, write, fhandle, RC_REPLBUFF, 1+7+22+4), + PROC(create, create, create, fhandle2, RC_REPLBUFF, 1+(1+9+22)+7+22), + PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, 1+(1+9+22)+7+22), + PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF, 1+(1+9+22)+7+22), + PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF, 1+(1+9+22)+7+22), + PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF, 1+7+22), + PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF, 1+7+22), + PROC(rename, rename, rename, fhandle2, RC_REPLBUFF, 1+7+22+7+22), + PROC(link, link, link, fhandle2, RC_REPLBUFF, 1+22+7+22), + PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE, 0), + PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE, 0), + PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE, 1+14), + PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE, 1+13), + PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE, 1+6), + PROC(commit, commit, commit, fhandle, RC_NOCACHE, 1+7+22+2), }; diff -u --recursive --new-file linux-2.4.19-fix_lockd4/fs/nfsd/nfsproc.c linux-2.4.19-neilb/fs/nfsd/nfsproc.c --- linux-2.4.19-fix_lockd4/fs/nfsd/nfsproc.c Tue Feb 5 08:52:52 2002 +++ linux-2.4.19-neilb/fs/nfsd/nfsproc.c Thu Aug 1 12:36:26 2002 @@ -148,6 +148,7 @@ argp->count); argp->count = avail << 2; } + svc_reserve(rqstp, (19<<2) + argp->count + 4); resp->count = argp->count; nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), @@ -522,7 +523,7 @@ #define nfssvc_release_none NULL struct nfsd_void { int dummy; }; -#define PROC(name, argt, rest, relt, cache) \ +#define PROC(name, argt, rest, relt, cache, respsize) \ { (svc_procfunc) nfsd_proc_##name, \ (kxdrproc_t) nfssvc_decode_##argt, \ (kxdrproc_t) nfssvc_encode_##rest, \ @@ -530,27 +531,28 @@ sizeof(struct nfsd_##argt), \ sizeof(struct nfsd_##rest), \ 0, \ - cache \ + cache, \ + respsize, \ } struct svc_procedure nfsd_procedures2[18] = { - PROC(null, void, void, none, RC_NOCACHE), - PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE), - PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF), - PROC(none, void, void, none, RC_NOCACHE), - PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE), - PROC(readlink, fhandle, readlinkres, none, RC_NOCACHE), - PROC(read, readargs, readres, fhandle, RC_NOCACHE), - PROC(none, void, void, none, RC_NOCACHE), - PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF), - PROC(create, createargs, diropres, fhandle, RC_REPLBUFF), - PROC(remove, diropargs, void, none, RC_REPLSTAT), - PROC(rename, renameargs, void, none, RC_REPLSTAT), - PROC(link, linkargs, void, none, RC_REPLSTAT), - PROC(symlink, symlinkargs, void, none, RC_REPLSTAT), - PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF), - PROC(rmdir, diropargs, void, none, RC_REPLSTAT), - PROC(readdir, readdirargs, readdirres, none, RC_REPLBUFF), - PROC(statfs, fhandle, statfsres, none, RC_NOCACHE), + PROC(null, void, void, none, RC_NOCACHE, 1), + PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, 1+18), + PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF, 1+18), + PROC(none, void, void, none, RC_NOCACHE, 1), + PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, 1+8+18), + PROC(readlink, fhandle, readlinkres, none, RC_NOCACHE, 1+1+256), + PROC(read, readargs, readres, fhandle, RC_NOCACHE, 1+18+1+NFSSVC_MAXBLKSIZE), + PROC(none, void, void, none, RC_NOCACHE, 1), + PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, 1+18), + PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, 1+8+18), + PROC(remove, diropargs, void, none, RC_REPLSTAT, 1), + PROC(rename, renameargs, void, none, RC_REPLSTAT, 1), + PROC(link, linkargs, void, none, RC_REPLSTAT, 1), + PROC(symlink, symlinkargs, void, none, RC_REPLSTAT, 1), + PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF, 1+8+18), + PROC(rmdir, diropargs, void, none, RC_REPLSTAT, 1), + PROC(readdir, readdirargs, readdirres, none, RC_REPLBUFF, 0), + PROC(statfs, fhandle, statfsres, none, RC_NOCACHE, 1+5), }; diff -u --recursive --new-file linux-2.4.19-fix_lockd4/fs/nfsd/nfssvc.c linux-2.4.19-neilb/fs/nfsd/nfssvc.c --- linux-2.4.19-fix_lockd4/fs/nfsd/nfssvc.c Fri May 3 08:37:11 2002 +++ linux-2.4.19-neilb/fs/nfsd/nfssvc.c Thu Aug 1 12:36:26 2002 @@ -95,7 +95,7 @@ if (error < 0) goto failure; -#if 0 /* Don't even pretend that TCP works. It doesn't. */ +#if CONFIG_NFSD_TCP error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); if (error < 0) goto failure; @@ -189,7 +189,7 @@ * recvfrom routine. */ while ((err = svc_recv(serv, rqstp, - MAX_SCHEDULE_TIMEOUT)) == -EAGAIN) + 5*60*HZ)) == -EAGAIN) ; if (err < 0) break; diff -u --recursive --new-file linux-2.4.19-fix_lockd4/fs/nfsd/nfsxdr.c linux-2.4.19-neilb/fs/nfsd/nfsxdr.c --- linux-2.4.19-fix_lockd4/fs/nfsd/nfsxdr.c Tue Feb 5 08:52:41 2002 +++ linux-2.4.19-neilb/fs/nfsd/nfsxdr.c Thu Aug 1 12:36:26 2002 @@ -379,7 +379,7 @@ { struct statfs *stat = &resp->stats; - *p++ = htonl(8 * 1024); /* max transfer size */ + *p++ = htonl(NFSSVC_MAXBLKSIZE); /* max transfer size */ *p++ = htonl(stat->f_bsize); *p++ = htonl(stat->f_blocks); *p++ = htonl(stat->f_bfree); diff -u --recursive --new-file linux-2.4.19-fix_lockd4/include/linux/nfsd/const.h linux-2.4.19-neilb/include/linux/nfsd/const.h --- linux-2.4.19-fix_lockd4/include/linux/nfsd/const.h Tue Feb 5 18:39:41 2002 +++ linux-2.4.19-neilb/include/linux/nfsd/const.h Thu Aug 1 12:36:26 2002 @@ -19,9 +19,9 @@ #define NFSSVC_MAXVERS 3 /* - * Maximum blocksize supported by daemon currently at 8K + * Maximum blocksize supported by daemon currently at 32K */ -#define NFSSVC_MAXBLKSIZE 8192 +#define NFSSVC_MAXBLKSIZE (32*1024) #ifdef __KERNEL__ diff -u --recursive --new-file linux-2.4.19-fix_lockd4/include/linux/sunrpc/sched.h linux-2.4.19-neilb/include/linux/sunrpc/sched.h --- linux-2.4.19-fix_lockd4/include/linux/sunrpc/sched.h Thu Aug 1 12:10:17 2002 +++ linux-2.4.19-neilb/include/linux/sunrpc/sched.h Thu Aug 1 12:36:26 2002 @@ -34,13 +34,11 @@ * This is the RPC task struct */ struct rpc_task { - struct rpc_task * tk_prev; /* wait queue links */ - struct rpc_task * tk_next; + struct list_head tk_list; /* wait queue links */ #ifdef RPC_DEBUG unsigned long tk_magic; /* 0xf00baa */ #endif - struct rpc_task * tk_next_task; /* global list of tasks */ - struct rpc_task * tk_prev_task; /* global list of tasks */ + struct list_head tk_task; /* global list of tasks */ struct rpc_clnt * tk_client; /* RPC client */ struct rpc_rqst * tk_rqstp; /* RPC request */ int tk_status; /* result of last operation */ @@ -86,6 +84,20 @@ #define tk_auth tk_client->cl_auth #define tk_xprt tk_client->cl_xprt +/* support walking a list of tasks on a wait queue */ +#define task_for_each(task, pos, head) \ + list_for_each(pos, head) \ + if ((task=list_entry(pos, struct rpc_task, tk_list)),1) + +#define task_for_first(task, head) \ + if (!list_empty(head) && \ + ((task=list_entry((head)->next, struct rpc_task, tk_list)),1)) + +/* .. and walking list of all tasks */ +#define alltask_for_each(task, pos, head) \ + list_for_each(pos, head) \ + if ((task=list_entry(pos, struct rpc_task, tk_task)),1) + typedef void (*rpc_action)(struct rpc_task *); /* @@ -131,16 +143,24 @@ * RPC synchronization objects */ struct rpc_wait_queue { - struct rpc_task * task; + struct list_head tasks; #ifdef RPC_DEBUG char * name; #endif }; #ifndef RPC_DEBUG -# define RPC_INIT_WAITQ(name) ((struct rpc_wait_queue) { NULL }) +# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var)}) +# define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var.tasks,qname) +# define INIT_RPC_WAITQ(ptr,qname) do { \ + INIT_LIST_HEAD(&(ptr)->tasks); \ + } while(0) #else -# define RPC_INIT_WAITQ(name) ((struct rpc_wait_queue) { NULL, name }) +# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var.tasks), qname}) +# define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname) +# define INIT_RPC_WAITQ(ptr,qname) do { \ + INIT_LIST_HEAD(&(ptr)->tasks); (ptr)->name = qname; \ + } while(0) #endif /* diff -u --recursive --new-file linux-2.4.19-fix_lockd4/include/linux/sunrpc/svc.h linux-2.4.19-neilb/include/linux/sunrpc/svc.h --- linux-2.4.19-fix_lockd4/include/linux/sunrpc/svc.h Tue Feb 5 18:39:41 2002 +++ linux-2.4.19-neilb/include/linux/sunrpc/svc.h Thu Aug 1 12:36:26 2002 @@ -26,8 +26,8 @@ * We currently do not support more than one RPC program per daemon. */ struct svc_serv { - struct svc_rqst * sv_threads; /* idle server threads */ - struct svc_sock * sv_sockets; /* pending sockets */ + struct list_head sv_threads; /* idle server threads */ + struct list_head sv_sockets; /* pending sockets */ struct svc_program * sv_program; /* RPC program */ struct svc_stat * sv_stats; /* RPC statistics */ spinlock_t sv_lock; @@ -35,7 +35,9 @@ unsigned int sv_bufsz; /* datagram buffer size */ unsigned int sv_xdrsize; /* XDR buffer size */ - struct svc_sock * sv_allsocks; /* all sockets */ + struct list_head sv_permsocks; /* all permanent sockets */ + struct list_head sv_tempsocks; /* all temporary sockets */ + int sv_tmpcnt; /* count of temporary sockets */ char * sv_name; /* service name */ }; @@ -88,8 +90,7 @@ * NOTE: First two items must be prev/next. */ struct svc_rqst { - struct svc_rqst * rq_prev; /* idle list */ - struct svc_rqst * rq_next; + struct list_head rq_list; /* idle list */ struct svc_sock * rq_sock; /* socket */ struct sockaddr_in rq_addr; /* peer address */ int rq_addrlen; @@ -114,6 +115,10 @@ void * rq_argp; /* decoded arguments */ void * rq_resp; /* xdr'd results */ + int rq_reserved; /* space on socket outq + * reserved for this request + */ + /* Catering to nfsd */ struct svc_client * rq_client; /* RPC peer info */ struct svc_cacherep * rq_cacherep; /* cache info */ @@ -162,6 +167,7 @@ unsigned int pc_ressize; /* result struct size */ unsigned int pc_count; /* call count */ unsigned int pc_cachetype; /* cache info (NFS) */ + unsigned int pc_xdrressize; /* maximum size of XDR reply */ }; /* @@ -179,5 +185,6 @@ int svc_process(struct svc_serv *, struct svc_rqst *); int svc_register(struct svc_serv *, int, unsigned short); void svc_wake_up(struct svc_serv *); +void svc_reserve(struct svc_rqst *rqstp, int space); #endif /* SUNRPC_SVC_H */ diff -u --recursive --new-file linux-2.4.19-fix_lockd4/include/linux/sunrpc/svcsock.h linux-2.4.19-neilb/include/linux/sunrpc/svcsock.h --- linux-2.4.19-fix_lockd4/include/linux/sunrpc/svcsock.h Tue Feb 5 18:39:41 2002 +++ linux-2.4.19-neilb/include/linux/sunrpc/svcsock.h Thu Aug 1 12:36:26 2002 @@ -13,38 +13,38 @@ /* * RPC server socket. - * NOTE: First two items must be prev/next. */ struct svc_sock { - struct svc_sock * sk_prev; /* list of ready sockets */ - struct svc_sock * sk_next; - struct svc_sock * sk_list; /* list of all sockets */ + struct list_head sk_ready; /* list of ready sockets */ + struct list_head sk_list; /* list of all sockets */ struct socket * sk_sock; /* berkeley socket layer */ struct sock * sk_sk; /* INET layer */ - spinlock_t sk_lock; struct svc_serv * sk_server; /* service for this socket */ unsigned char sk_inuse; /* use count */ - unsigned char sk_busy; /* enqueued/receiving */ - unsigned char sk_conn; /* conn pending */ - unsigned char sk_close; /* dead or dying */ - int sk_data; /* data pending */ - unsigned int sk_temp : 1, /* temp socket */ - sk_qued : 1, /* on serv->sk_sockets */ - sk_dead : 1; /* socket closed */ + unsigned int sk_flags; +#define SK_BUSY 0 /* enqueued/receiving */ +#define SK_CONN 1 /* conn pending */ +#define SK_CLOSE 2 /* dead or dying */ +#define SK_DATA 3 /* data pending */ +#define SK_TEMP 4 /* temp (TCP) socket */ +#define SK_QUED 5 /* on serv->sk_sockets */ +#define SK_DEAD 6 /* socket closed */ + + int sk_reserved; /* space on outq that is reserved */ + int (*sk_recvfrom)(struct svc_rqst *rqstp); int (*sk_sendto)(struct svc_rqst *rqstp); /* We keep the old state_change and data_ready CB's here */ void (*sk_ostate)(struct sock *); void (*sk_odata)(struct sock *, int bytes); + void (*sk_owspace)(struct sock *); /* private TCP part */ int sk_reclen; /* length of record */ int sk_tcplen; /* current read length */ - - /* Debugging */ - struct svc_rqst * sk_rqstp; + time_t sk_lastrecv; /* time of last received request */ }; /* @@ -55,5 +55,6 @@ int svc_recv(struct svc_serv *, struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); +void svc_sock_update_bufs(struct svc_serv *serv); #endif /* SUNRPC_SVCSOCK_H */ diff -u --recursive --new-file linux-2.4.19-fix_lockd4/include/linux/sunrpc/types.h linux-2.4.19-neilb/include/linux/sunrpc/types.h --- linux-2.4.19-fix_lockd4/include/linux/sunrpc/types.h Tue Feb 5 08:43:00 2002 +++ linux-2.4.19-neilb/include/linux/sunrpc/types.h Thu Aug 1 12:36:26 2002 @@ -12,60 +12,7 @@ #include #include #include - -/* - * These are the RPC list manipulation primitives used everywhere. - */ -struct rpc_listitem { - struct rpc_listitem * prev; - struct rpc_listitem * next; -}; - -static __inline__ void -__rpc_append_list(struct rpc_listitem **q, struct rpc_listitem *item) -{ - struct rpc_listitem *next, *prev; - - if (!(next = *q)) { - *q = item->next = item->prev = item; - } else { - prev = next->prev; - prev->next = item; - next->prev = item; - item->next = next; - item->prev = prev; - } -} - -static __inline__ void -__rpc_insert_list(struct rpc_listitem **q, struct rpc_listitem *item) -{ - __rpc_append_list(q, item); - *q = item; -} - -static __inline__ void -__rpc_remove_list(struct rpc_listitem **q, struct rpc_listitem *item) -{ - struct rpc_listitem *prev = item->prev, - *next = item->next; - - if (item != prev) { - next->prev = prev; - prev->next = next; - } else { - next = NULL; - } - if (*q == item) - *q = next; -} - -#define rpc_insert_list(q, i) \ - __rpc_insert_list((struct rpc_listitem **) q, (struct rpc_listitem *) i) -#define rpc_append_list(q, i) \ - __rpc_append_list((struct rpc_listitem **) q, (struct rpc_listitem *) i) -#define rpc_remove_list(q, i) \ - __rpc_remove_list((struct rpc_listitem **) q, (struct rpc_listitem *) i) +#include /* * Shorthands diff -u --recursive --new-file linux-2.4.19-fix_lockd4/net/sunrpc/clnt.c linux-2.4.19-neilb/net/sunrpc/clnt.c --- linux-2.4.19-fix_lockd4/net/sunrpc/clnt.c Thu Aug 1 12:24:30 2002 +++ linux-2.4.19-neilb/net/sunrpc/clnt.c Thu Aug 1 12:36:26 2002 @@ -79,10 +79,6 @@ dprintk("RPC: creating %s client for %s (xprt %p)\n", program->name, servname, xprt); -#ifdef RPC_DEBUG - rpc_register_sysctl(); -#endif - if (!xprt) goto out; if (vers >= program->nrvers || !(version = program->version[vers])) @@ -104,7 +100,7 @@ clnt->cl_vers = version->number; clnt->cl_prot = xprt->prot; clnt->cl_stats = program->stats; - clnt->cl_bindwait = RPC_INIT_WAITQ("bindwait"); + INIT_RPC_WAITQ(&clnt->cl_bindwait, "bindwait"); if (!clnt->cl_port) clnt->cl_autobind = 1; diff -u --recursive --new-file linux-2.4.19-fix_lockd4/net/sunrpc/sched.c linux-2.4.19-neilb/net/sunrpc/sched.c --- linux-2.4.19-fix_lockd4/net/sunrpc/sched.c Thu Aug 1 12:10:17 2002 +++ linux-2.4.19-neilb/net/sunrpc/sched.c Thu Aug 1 12:36:27 2002 @@ -41,23 +41,23 @@ * handler, or while executing another RPC task, it is put on * schedq, and rpciod is woken up. */ -static struct rpc_wait_queue schedq = RPC_INIT_WAITQ("schedq"); +static RPC_WAITQ(schedq, "schedq"); /* * RPC tasks that create another task (e.g. for contacting the portmapper) * will wait on this queue for their child's completion */ -static struct rpc_wait_queue childq = RPC_INIT_WAITQ("childq"); +static RPC_WAITQ(childq, "childq"); /* * RPC tasks sit here while waiting for conditions to improve. */ -static struct rpc_wait_queue delay_queue = RPC_INIT_WAITQ("delayq"); +static RPC_WAITQ(delay_queue, "delayq"); /* * All RPC tasks are linked into this list */ -static struct rpc_task * all_tasks; +static LIST_HEAD(all_tasks); /* * rpciod-related stuff @@ -194,9 +194,9 @@ return -EWOULDBLOCK; } if (RPC_IS_SWAPPER(task)) - rpc_insert_list(&queue->task, task); + list_add(&task->tk_list, &queue->tasks); else - rpc_append_list(&queue->task, task); + list_add_tail(&task->tk_list, &queue->tasks); task->tk_rpcwait = queue; dprintk("RPC: %4d added to queue %p \"%s\"\n", @@ -228,7 +228,7 @@ if (!queue) return; - rpc_remove_list(&queue->task, task); + list_del(&task->tk_list); task->tk_rpcwait = NULL; dprintk("RPC: %4d removed from queue %p \"%s\"\n", @@ -425,11 +425,11 @@ struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue) { - struct rpc_task *task; + struct rpc_task *task = NULL; dprintk("RPC: wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue)); spin_lock_bh(&rpc_queue_lock); - if ((task = queue->task) != 0) + task_for_first(task, &queue->tasks) __rpc_wake_up_task(task); spin_unlock_bh(&rpc_queue_lock); @@ -445,9 +445,12 @@ void rpc_wake_up(struct rpc_wait_queue *queue) { + struct rpc_task *task; + spin_lock_bh(&rpc_queue_lock); - while (queue->task) - __rpc_wake_up_task(queue->task); + while (!list_empty(&queue->tasks)) + task_for_first(task, &queue->tasks) + __rpc_wake_up_task(task); spin_unlock_bh(&rpc_queue_lock); } @@ -461,12 +464,14 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) { - struct rpc_task *task; + struct rpc_task *task; spin_lock_bh(&rpc_queue_lock); - while ((task = queue->task) != NULL) { - task->tk_status = status; - __rpc_wake_up_task(task); + while (!list_empty(&queue->tasks)) { + task_for_first(task, &queue->tasks) { + task->tk_status = status; + __rpc_wake_up_task(task); + } } spin_unlock_bh(&rpc_queue_lock); } @@ -651,16 +656,17 @@ dprintk("RPC: rpc_schedule enter\n"); while (1) { spin_lock_bh(&rpc_queue_lock); - if (!(task = schedq.task)) { + + task_for_first(task, &schedq.tasks) { + __rpc_remove_wait_queue(task); + spin_unlock_bh(&rpc_queue_lock); + + __rpc_execute(task); + } else { spin_unlock_bh(&rpc_queue_lock); break; } - __rpc_remove_wait_queue(task); - spin_unlock_bh(&rpc_queue_lock); - - __rpc_execute(task); - if (++count >= 200 || current->need_resched) { count = 0; schedule(); @@ -755,11 +761,7 @@ /* Add to global list of all tasks */ spin_lock(&rpc_sched_lock); - task->tk_next_task = all_tasks; - task->tk_prev_task = NULL; - if (all_tasks) - all_tasks->tk_prev_task = task; - all_tasks = task; + list_add(&task->tk_task, &all_tasks); spin_unlock(&rpc_sched_lock); if (clnt) @@ -818,8 +820,6 @@ void rpc_release_task(struct rpc_task *task) { - struct rpc_task *next, *prev; - dprintk("RPC: %4d release task\n", task->tk_pid); #ifdef RPC_DEBUG @@ -833,15 +833,7 @@ /* Remove from global task list */ spin_lock(&rpc_sched_lock); - prev = task->tk_prev_task; - next = task->tk_next_task; - if (next) - next->tk_prev_task = prev; - if (prev) - prev->tk_next_task = next; - else - all_tasks = next; - task->tk_next_task = task->tk_prev_task = NULL; + list_del(&task->tk_task); spin_unlock(&rpc_sched_lock); /* Protect the execution below. */ @@ -895,14 +887,13 @@ rpc_find_parent(struct rpc_task *child) { struct rpc_task *task, *parent; + struct list_head *le; parent = (struct rpc_task *) child->tk_calldata; - if ((task = childq.task) != NULL) { - do { - if (task == parent) - return parent; - } while ((task = task->tk_next) != childq.task); - } + task_for_each(task, le, &childq.tasks) + if (task == parent) + return parent; + return NULL; } @@ -956,7 +947,8 @@ void rpc_killall_tasks(struct rpc_clnt *clnt) { - struct rpc_task **q, *rovr; + struct rpc_task *rovr; + struct list_head *le; dprintk("RPC: killing all tasks for client %p\n", clnt); @@ -964,13 +956,12 @@ * Spin lock all_tasks to prevent changes... */ spin_lock(&rpc_sched_lock); - for (q = &all_tasks; (rovr = *q); q = &rovr->tk_next_task) { + alltask_for_each(rovr, le, &all_tasks) if (!clnt || rovr->tk_client == clnt) { rovr->tk_flags |= RPC_TASK_KILLED; rpc_exit(rovr, -EIO); rpc_wake_up_task(rovr); } - } spin_unlock(&rpc_sched_lock); } @@ -979,7 +970,7 @@ static inline int rpciod_task_pending(void) { - return schedq.task != NULL; + return !list_empty(&schedq.tasks); } @@ -1031,7 +1022,7 @@ } dprintk("RPC: rpciod shutdown commences\n"); - if (all_tasks) { + if (!list_empty(&all_tasks)) { printk(KERN_ERR "rpciod: active tasks at shutdown?!\n"); rpciod_killall(); } @@ -1049,11 +1040,11 @@ { unsigned long flags; - while (all_tasks) { + while (!list_empty(&all_tasks)) { current->sigpending = 0; rpc_killall_tasks(NULL); __rpc_schedule(); - if (all_tasks) { + if (!list_empty(&all_tasks)) { dprintk("rpciod_killall: waiting for tasks to exit\n"); current->policy |= SCHED_YIELD; schedule(); @@ -1150,25 +1141,23 @@ #ifdef RPC_DEBUG void rpc_show_tasks(void) { - struct rpc_task *t = all_tasks, *next; + struct list_head *le; + struct rpc_task *t; spin_lock(&rpc_sched_lock); - t = all_tasks; - if (!t) { + if (list_empty(&all_tasks)) { spin_unlock(&rpc_sched_lock); return; } printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout " "-rpcwait -action- --exit--\n"); - for (; t; t = next) { - next = t->tk_next_task; + alltask_for_each(t, le, &all_tasks) printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n", t->tk_pid, t->tk_msg.rpc_proc, t->tk_flags, t->tk_status, t->tk_client, t->tk_client->cl_prog, t->tk_rqstp, t->tk_timeout, t->tk_rpcwait ? rpc_qname(t->tk_rpcwait) : " ", t->tk_action, t->tk_exit); - } spin_unlock(&rpc_sched_lock); } #endif diff -u --recursive --new-file linux-2.4.19-fix_lockd4/net/sunrpc/stats.c linux-2.4.19-neilb/net/sunrpc/stats.c --- linux-2.4.19-fix_lockd4/net/sunrpc/stats.c Wed Jan 16 15:55:58 2002 +++ linux-2.4.19-neilb/net/sunrpc/stats.c Thu Aug 1 12:36:27 2002 @@ -15,6 +15,7 @@ #define __NO_VERSION__ #include +#include #include #include #include @@ -182,10 +183,9 @@ } } -#ifdef MODULE -int -init_module(void) +static int __init +init_sunrpc(void) { #ifdef RPC_DEBUG rpc_register_sysctl(); @@ -194,13 +194,14 @@ return 0; } -void -cleanup_module(void) +static void __exit +cleanup_sunrpc(void) { #ifdef RPC_DEBUG rpc_unregister_sysctl(); #endif rpc_proc_exit(); } -#endif MODULE_LICENSE("GPL"); +module_init(init_sunrpc); +module_exit(cleanup_sunrpc); diff -u --recursive --new-file linux-2.4.19-fix_lockd4/net/sunrpc/sunrpc_syms.c linux-2.4.19-neilb/net/sunrpc/sunrpc_syms.c --- linux-2.4.19-fix_lockd4/net/sunrpc/sunrpc_syms.c Thu Aug 1 12:24:30 2002 +++ linux-2.4.19-neilb/net/sunrpc/sunrpc_syms.c Thu Aug 1 12:36:27 2002 @@ -78,6 +78,7 @@ EXPORT_SYMBOL(svc_recv); EXPORT_SYMBOL(svc_wake_up); EXPORT_SYMBOL(svc_makesock); +EXPORT_SYMBOL(svc_reserve); /* RPC statistics */ #ifdef CONFIG_PROC_FS diff -u --recursive --new-file linux-2.4.19-fix_lockd4/net/sunrpc/svc.c linux-2.4.19-neilb/net/sunrpc/svc.c --- linux-2.4.19-fix_lockd4/net/sunrpc/svc.c Tue Feb 5 08:44:56 2002 +++ linux-2.4.19-neilb/net/sunrpc/svc.c Thu Aug 1 12:36:27 2002 @@ -31,10 +31,6 @@ { struct svc_serv *serv; -#ifdef RPC_DEBUG - rpc_register_sysctl(); -#endif - if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL))) return NULL; @@ -44,6 +40,10 @@ serv->sv_stats = prog->pg_stats; serv->sv_bufsz = bufsize? bufsize : 4096; serv->sv_xdrsize = xdrsize; + INIT_LIST_HEAD(&serv->sv_threads); + INIT_LIST_HEAD(&serv->sv_sockets); + INIT_LIST_HEAD(&serv->sv_tempsocks); + INIT_LIST_HEAD(&serv->sv_permsocks); spin_lock_init(&serv->sv_lock); serv->sv_name = prog->pg_name; @@ -67,13 +67,25 @@ serv->sv_nrthreads); if (serv->sv_nrthreads) { - if (--(serv->sv_nrthreads) != 0) + if (--(serv->sv_nrthreads) != 0) { + svc_sock_update_bufs(serv); return; + } } else printk("svc_destroy: no threads for serv=%p!\n", serv); - while ((svsk = serv->sv_allsocks) != NULL) + while (!list_empty(&serv->sv_tempsocks)) { + svsk = list_entry(serv->sv_tempsocks.next, + struct svc_sock, + sk_list); + svc_delete_socket(svsk); + } + while (!list_empty(&serv->sv_permsocks)) { + svsk = list_entry(serv->sv_permsocks.next, + struct svc_sock, + sk_list); svc_delete_socket(svsk); + } /* Unregister service with the portmapper */ svc_register(serv, 0, 0); @@ -138,6 +150,7 @@ error = kernel_thread((int (*)(void *)) func, rqstp, 0); if (error < 0) goto out_thread; + svc_sock_update_bufs(serv); error = 0; out: return error; @@ -296,6 +309,12 @@ memset(rqstp->rq_argp, 0, procp->pc_argsize); memset(rqstp->rq_resp, 0, procp->pc_ressize); + /* un-reserve some of the out-queue now that we have a + * better idea of reply size + */ + if (procp->pc_xdrressize) + svc_reserve(rqstp, procp->pc_xdrressize<<2); + /* Call the function that processes the request. */ if (!versp->vs_dispatch) { /* Decode arguments */ diff -u --recursive --new-file linux-2.4.19-fix_lockd4/net/sunrpc/svcsock.c linux-2.4.19-neilb/net/sunrpc/svcsock.c --- linux-2.4.19-fix_lockd4/net/sunrpc/svcsock.c Tue Feb 5 08:42:03 2002 +++ linux-2.4.19-neilb/net/sunrpc/svcsock.c Thu Aug 1 12:36:27 2002 @@ -44,10 +44,19 @@ /* SMP locking strategy: * - * svc_sock->sk_lock and svc_serv->sv_lock protect their - * respective structures. + * svc_serv->sv_lock protects most stuff for that service. + * + * Some flags can be set to certain values at any time + * providing that certain rules are followed: + * + * SK_BUSY can be set to 0 at any time. + * svc_sock_enqueue must be called afterwards + * SK_CONN, SK_DATA, can be set or cleared at any time. + * after a set, svc_sock_enqueue must be called. + * after a clear, the socket must be read/accepted + * if this succeeds, it must be set again. + * SK_CLOSE can set at any time. It is never cleared. * - * Antideadlock ordering is sk_lock --> sv_lock. */ #define RPCDBG_FACILITY RPCDBG_SVCSOCK @@ -62,11 +71,14 @@ /* * Queue up an idle server thread. Must have serv->sv_lock held. + * Note: this is really a stack rather than a queue, so that we only + * use as many different threads as we need, and the rest don't polute + * the cache. */ static inline void svc_serv_enqueue(struct svc_serv *serv, struct svc_rqst *rqstp) { - rpc_append_list(&serv->sv_threads, rqstp); + list_add(&rqstp->rq_list, &serv->sv_threads); } /* @@ -75,7 +87,7 @@ static inline void svc_serv_dequeue(struct svc_serv *serv, struct svc_rqst *rqstp) { - rpc_remove_list(&serv->sv_threads, rqstp); + list_del(&rqstp->rq_list); } /* @@ -98,7 +110,6 @@ * Queue up a socket with data pending. If there are idle nfsd * processes, wake 'em up. * - * This must be called with svsk->sk_lock held. */ static void svc_sock_enqueue(struct svc_sock *svsk) @@ -106,26 +117,44 @@ struct svc_serv *serv = svsk->sk_server; struct svc_rqst *rqstp; - /* NOTE: Local BH is already disabled by our caller. */ - spin_lock(&serv->sv_lock); + if (!(svsk->sk_flags & + ( (1<sv_lock); - if (serv->sv_threads && serv->sv_sockets) + if (!list_empty(&serv->sv_threads) && + !list_empty(&serv->sv_sockets)) printk(KERN_ERR "svc_sock_enqueue: threads and sockets both waiting??\n"); - if (svsk->sk_busy) { + if (test_bit(SK_BUSY, &svsk->sk_flags)) { /* Don't enqueue socket while daemon is receiving */ dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk); goto out_unlock; } + if (((svsk->sk_reserved + serv->sv_bufsz)*2 + > sock_wspace(svsk->sk_sk)) + && !test_bit(SK_CLOSE, &svsk->sk_flags) + && !test_bit(SK_CONN, &svsk->sk_flags)) { + /* Don't enqueue while not enough space for reply */ + dprintk("svc: socket %p no space, %d > %ld, not enqueued\n", + svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz, + sock_wspace(svsk->sk_sk)); + goto out_unlock; + } + /* Mark socket as busy. It will remain in this state until the * server has processed all pending data and put the socket back * on the idle list. */ - svsk->sk_busy = 1; + set_bit(SK_BUSY, &svsk->sk_flags); - if ((rqstp = serv->sv_threads) != NULL) { + if (!list_empty(&serv->sv_threads)) { + rqstp = list_entry(serv->sv_threads.next, + struct svc_rqst, + rq_list); dprintk("svc: socket %p served by daemon %p\n", svsk->sk_sk, rqstp); svc_serv_dequeue(serv, rqstp); @@ -135,15 +164,17 @@ rqstp, rqstp->rq_sock); rqstp->rq_sock = svsk; svsk->sk_inuse++; + rqstp->rq_reserved = serv->sv_bufsz; + svsk->sk_reserved += rqstp->rq_reserved; wake_up(&rqstp->rq_wait); } else { dprintk("svc: socket %p put into queue\n", svsk->sk_sk); - rpc_append_list(&serv->sv_sockets, svsk); - svsk->sk_qued = 1; + list_add_tail(&svsk->sk_ready, &serv->sv_sockets); + set_bit(SK_QUED, &svsk->sk_flags); } out_unlock: - spin_unlock(&serv->sv_lock); + spin_unlock_bh(&serv->sv_lock); } /* @@ -154,71 +185,69 @@ { struct svc_sock *svsk; - if ((svsk = serv->sv_sockets) != NULL) - rpc_remove_list(&serv->sv_sockets, svsk); + if (list_empty(&serv->sv_sockets)) + return NULL; - if (svsk) { - dprintk("svc: socket %p dequeued, inuse=%d\n", - svsk->sk_sk, svsk->sk_inuse); - svsk->sk_qued = 0; - } + svsk = list_entry(serv->sv_sockets.next, + struct svc_sock, sk_ready); + list_del(&svsk->sk_ready); + + dprintk("svc: socket %p dequeued, inuse=%d\n", + svsk->sk_sk, svsk->sk_inuse); + clear_bit(SK_QUED, &svsk->sk_flags); return svsk; } /* - * Having read count bytes from a socket, check whether it + * Having read something from a socket, check whether it * needs to be re-enqueued. + * Note: SK_DATA only gets cleared when a read-attempt finds + * no (or insufficient) data. */ static inline void -svc_sock_received(struct svc_sock *svsk, int count) +svc_sock_received(struct svc_sock *svsk) { - spin_lock_bh(&svsk->sk_lock); - if ((svsk->sk_data -= count) < 0) { - printk(KERN_NOTICE "svc: sk_data negative!\n"); - svsk->sk_data = 0; - } - svsk->sk_rqstp = NULL; /* XXX */ - svsk->sk_busy = 0; - if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) { - dprintk("svc: socket %p re-enqueued after receive\n", - svsk->sk_sk); - svc_sock_enqueue(svsk); - } - spin_unlock_bh(&svsk->sk_lock); + clear_bit(SK_BUSY, &svsk->sk_flags); + svc_sock_enqueue(svsk); } -/* - * Dequeue a new connection. + +/** + * svc_reserve - change the space reserved for the reply to a request. + * @rqstp: The request in question + * @space: new max space to reserve + * + * Each request reserves some space on the output queue of the socket + * to make sure the reply fits. This function reduces that reserved + * space to be the amount of space used already, plus @space. + * */ -static inline void -svc_sock_accepted(struct svc_sock *svsk) +void svc_reserve(struct svc_rqst *rqstp, int space) { - spin_lock_bh(&svsk->sk_lock); - svsk->sk_busy = 0; - svsk->sk_conn--; - if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) { - dprintk("svc: socket %p re-enqueued after accept\n", - svsk->sk_sk); - svc_sock_enqueue(svsk); - } - spin_unlock_bh(&svsk->sk_lock); + space += rqstp->rq_resbuf.len<<2; + + if (space < rqstp->rq_reserved) { + struct svc_sock *svsk = rqstp->rq_sock; + spin_lock_bh(&svsk->sk_server->sv_lock); + svsk->sk_reserved -= (rqstp->rq_reserved - space); + rqstp->rq_reserved = space; + spin_unlock_bh(&svsk->sk_server->sv_lock); + + svc_sock_enqueue(svsk); + } } /* * Release a socket after use. */ static inline void -svc_sock_release(struct svc_rqst *rqstp) +svc_sock_put(struct svc_sock *svsk) { - struct svc_sock *svsk = rqstp->rq_sock; - struct svc_serv *serv = svsk->sk_server; - - svc_release_skb(rqstp); - rqstp->rq_sock = NULL; + struct svc_serv *serv = svsk->sk_server; spin_lock_bh(&serv->sv_lock); - if (!--(svsk->sk_inuse) && svsk->sk_dead) { + if (!--(svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) { spin_unlock_bh(&serv->sv_lock); dprintk("svc: releasing dead socket\n"); sock_release(svsk->sk_sock); @@ -228,6 +257,31 @@ spin_unlock_bh(&serv->sv_lock); } +static void +svc_sock_release(struct svc_rqst *rqstp) +{ + struct svc_sock *svsk = rqstp->rq_sock; + + svc_release_skb(rqstp); + + /* Reset response buffer and release + * the reservation. + * But first, check that enough space was reserved + * for the reply, otherwise we have a bug! + */ + if ((rqstp->rq_resbuf.len<<2) > rqstp->rq_reserved) + printk(KERN_ERR "RPC request reserved %d but used %d\n", + rqstp->rq_reserved, + rqstp->rq_resbuf.len<<2); + + rqstp->rq_resbuf.buf = rqstp->rq_resbuf.base; + rqstp->rq_resbuf.len = 0; + svc_reserve(rqstp, 0); + rqstp->rq_sock = NULL; + + svc_sock_put(svsk); +} + /* * External function to wake up a server waiting for data */ @@ -237,7 +291,10 @@ struct svc_rqst *rqstp; spin_lock_bh(&serv->sv_lock); - if ((rqstp = serv->sv_threads) != NULL) { + if (!list_empty(&serv->sv_threads)) { + rqstp = list_entry(serv->sv_threads.next, + struct svc_rqst, + rq_list); dprintk("svc: daemon %p woken up.\n", rqstp); /* svc_serv_dequeue(serv, rqstp); @@ -270,7 +327,13 @@ msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_flags = MSG_DONTWAIT; + /* This was MSG_DONTWAIT, but I now want it to wait. + * The only thing that it would wait for is memory and + * if we are fairly low on memory, then we aren't likely + * to make much progress anyway. + * sk->sndtimeo is set to 30seconds just in case. + */ + msg.msg_flags = 0; oldfs = get_fs(); set_fs(KERNEL_DS); len = sock_sendmsg(sock, &msg, buflen); @@ -340,6 +403,32 @@ } /* + * Set socket snd and rcv buffer lengths + */ +static inline void +svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv) +{ +#if 0 + mm_segment_t oldfs; + oldfs = get_fs(); set_fs(KERNEL_DS); + sock_setsockopt(sock, SOL_SOCKET, SO_SNDBUF, + (char*)&snd, sizeof(snd)); + sock_setsockopt(sock, SOL_SOCKET, SO_RCVBUF, + (char*)&rcv, sizeof(rcv)); +#else + /* sock_setsockopt limits use to sysctl_?mem_max, + * which isn't acceptable. Until that is made conditional + * on not having CAP_SYS_RESOURCE or similar, we go direct... + * DaveM said I could! + */ + lock_sock(sock->sk); + sock->sk->sndbuf = snd * 2; + sock->sk->rcvbuf = rcv * 2; + sock->sk->userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; + release_sock(sock->sk); +#endif +} +/* * INET callback when data has been received on the socket. */ static void @@ -350,17 +439,36 @@ if (!svsk) goto out; dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n", - svsk, sk, count, svsk->sk_busy); - spin_lock_bh(&svsk->sk_lock); - svsk->sk_data = 1; + svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags)); + set_bit(SK_DATA, &svsk->sk_flags); svc_sock_enqueue(svsk); - spin_unlock_bh(&svsk->sk_lock); out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); } /* + * INET callback when space is newly available on the socket. + */ +static void +svc_write_space(struct sock *sk) +{ + struct svc_sock *svsk = (struct svc_sock *)(sk->user_data); + + if (svsk) { + dprintk("svc: socket %p(inet %p), write_space busy=%d\n", + svsk, sk, test_bit(SK_BUSY, &svsk->sk_flags)); + svc_sock_enqueue(svsk); + } + + if (sk->sleep && waitqueue_active(sk->sleep)) { + printk(KERN_WARNING "RPC svc_write_space: some sleeping on %p\n", + svsk); + wake_up_interruptible(sk->sleep); + } +} + +/* * Receive a datagram from a UDP socket. */ static int @@ -372,20 +480,21 @@ u32 *data; int err, len; - svsk->sk_data = 0; + clear_bit(SK_DATA, &svsk->sk_flags); while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { - svc_sock_received(svsk, 0); + svc_sock_received(svsk); if (err == -EAGAIN) return err; /* possibly an icmp error */ dprintk("svc: recvfrom returned error %d\n", -err); } + set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */ /* Sorry. */ if (skb_is_nonlinear(skb)) { if (skb_linearize(skb, GFP_KERNEL) != 0) { kfree_skb(skb); - svc_sock_received(svsk, 0); + svc_sock_received(svsk); return 0; } } @@ -393,13 +502,11 @@ if (skb->ip_summed != CHECKSUM_UNNECESSARY) { if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { skb_free_datagram(svsk->sk_sk, skb); - svc_sock_received(svsk, 0); + svc_sock_received(svsk); return 0; } } - /* There may be more data */ - svsk->sk_data = 1; len = skb->len - sizeof(struct udphdr); data = (u32 *) (skb->data + sizeof(struct udphdr)); @@ -421,7 +528,7 @@ /* One down, maybe more to go... */ svsk->sk_sk->stamp = skb->stamp; - svc_sock_received(svsk, 0); + svc_sock_received(svsk); return len; } @@ -444,9 +551,6 @@ if (error == -ECONNREFUSED) /* ICMP error on earlier request. */ error = svc_sendto(rqstp, bufp->iov, bufp->nriov); - else if (error == -EAGAIN) - /* Ignore and wait for re-xmit */ - error = 0; return error; } @@ -455,6 +559,7 @@ svc_udp_init(struct svc_sock *svsk) { svsk->sk_sk->data_ready = svc_udp_data_ready; + svsk->sk_sk->write_space = svc_write_space; svsk->sk_recvfrom = svc_udp_recvfrom; svsk->sk_sendto = svc_udp_sendto; @@ -481,10 +586,8 @@ printk("svc: socket %p: no user data\n", sk); goto out; } - spin_lock_bh(&svsk->sk_lock); - svsk->sk_conn++; + set_bit(SK_CONN, &svsk->sk_flags); svc_sock_enqueue(svsk); - spin_unlock_bh(&svsk->sk_lock); out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible_all(sk->sleep); @@ -505,10 +608,8 @@ printk("svc: socket %p: no user data\n", sk); goto out; } - spin_lock_bh(&svsk->sk_lock); - svsk->sk_close = 1; + set_bit(SK_CLOSE, &svsk->sk_flags); svc_sock_enqueue(svsk); - spin_unlock_bh(&svsk->sk_lock); out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible_all(sk->sleep); @@ -523,10 +624,8 @@ sk, sk->user_data); if (!(svsk = (struct svc_sock *)(sk->user_data))) goto out; - spin_lock_bh(&svsk->sk_lock); - svsk->sk_data++; + set_bit(SK_DATA, &svsk->sk_flags); svc_sock_enqueue(svsk); - spin_unlock_bh(&svsk->sk_lock); out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); @@ -559,13 +658,14 @@ newsock->type = sock->type; newsock->ops = ops = sock->ops; + clear_bit(SK_CONN, &svsk->sk_flags); if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) { - if (net_ratelimit()) + if (err != -EAGAIN && net_ratelimit()) printk(KERN_WARNING "%s: accept failed (err %d)!\n", serv->sv_name, -err); goto failed; /* aborted connection or whatever */ } - + set_bit(SK_CONN, &svsk->sk_flags); slen = sizeof(sin); err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1); if (err < 0) { @@ -593,14 +693,45 @@ if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0))) goto failed; + /* make sure that a write doesn't block forever when + * low on memory + */ + newsock->sk->sndtimeo = HZ*30; + /* Precharge. Data may have arrived on the socket before we * installed the data_ready callback. */ - spin_lock_bh(&newsvsk->sk_lock); - newsvsk->sk_data = 1; - newsvsk->sk_temp = 1; + set_bit(SK_DATA, &newsvsk->sk_flags); svc_sock_enqueue(newsvsk); - spin_unlock_bh(&newsvsk->sk_lock); + + /* make sure that we don't have too many active connections. + * If we have, something must be dropped. + * We randomly choose between newest and oldest (in terms + * of recent activity) and drop it. + */ + if (serv->sv_tmpcnt > serv->sv_nrthreads*5) { + struct svc_sock *svsk = NULL; + spin_lock_bh(&serv->sv_lock); + if (!list_empty(&serv->sv_tempsocks)) { + if (net_random()&1) + svsk = list_entry(serv->sv_tempsocks.prev, + struct svc_sock, + sk_list); + else + svsk = list_entry(serv->sv_tempsocks.next, + struct svc_sock, + sk_list); + set_bit(SK_CLOSE, &svsk->sk_flags); + svsk->sk_inuse ++; + } + spin_unlock_bh(&serv->sv_lock); + + if (svsk) { + svc_sock_enqueue(svsk); + svc_sock_put(svsk); + } + + } if (serv->sv_stats) serv->sv_stats->nettcpconn++; @@ -621,23 +752,25 @@ struct svc_sock *svsk = rqstp->rq_sock; struct svc_serv *serv = svsk->sk_server; struct svc_buf *bufp = &rqstp->rq_argbuf; - int len, ready, used; + int len; dprintk("svc: tcp_recv %p data %d conn %d close %d\n", - svsk, svsk->sk_data, svsk->sk_conn, svsk->sk_close); + svsk, test_bit(SK_DATA, &svsk->sk_flags), + test_bit(SK_CONN, &svsk->sk_flags), + test_bit(SK_CLOSE, &svsk->sk_flags)); - if (svsk->sk_close) { + if (test_bit(SK_CLOSE, &svsk->sk_flags)) { svc_delete_socket(svsk); return 0; } - if (svsk->sk_conn) { + if (test_bit(SK_CONN, &svsk->sk_flags)) { svc_tcp_accept(svsk); - svc_sock_accepted(svsk); + svc_sock_received(svsk); return 0; } - ready = svsk->sk_data; + clear_bit(SK_DATA, &svsk->sk_flags); /* Receive data. If we haven't got the record length yet, get * the next four bytes. Otherwise try to gobble up as much as @@ -660,13 +793,17 @@ * bit set in the fragment length header. * But apparently no known nfs clients send fragmented * records. */ - /* FIXME: shutdown socket */ - printk(KERN_NOTICE "RPC: bad TCP reclen %08lx", + printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (non-terminal)\n", (unsigned long) svsk->sk_reclen); - return -EIO; + goto err_delete; } svsk->sk_reclen &= 0x7fffffff; dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen); + if (svsk->sk_reclen > (bufp->buflen<<2)) { + printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (large)\n", + (unsigned long) svsk->sk_reclen); + goto err_delete; + } } /* Check whether enough data is available */ @@ -675,21 +812,12 @@ goto error; if (len < svsk->sk_reclen) { - /* FIXME: if sk_reclen > window-size, then we will - * never be able to receive the record, so should - * shutdown the connection - */ dprintk("svc: incomplete TCP record (%d of %d)\n", len, svsk->sk_reclen); - svc_sock_received(svsk, ready); + svc_sock_received(svsk); return -EAGAIN; /* record not complete */ } - /* if we think there is only one more record to read, but - * it is bigger than we expect, then two records must have arrived - * together, so pretend we aren't using the record.. */ - if (len > svsk->sk_reclen && ready == 1) - used = 0; - else used = 1; + set_bit(SK_DATA, &svsk->sk_flags); /* Frob argbuf */ bufp->iov[0].iov_base += 4; @@ -716,20 +844,24 @@ svsk->sk_reclen = 0; svsk->sk_tcplen = 0; - svc_sock_received(svsk, used); + svc_sock_received(svsk); if (serv->sv_stats) serv->sv_stats->nettcpcnt++; return len; -error: + err_delete: + svc_delete_socket(svsk); + return -EAGAIN; + + error: if (len == -EAGAIN) { dprintk("RPC: TCP recvfrom got EAGAIN\n"); - svc_sock_received(svsk, ready); /* Clear data ready */ + svc_sock_received(svsk); } else { printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", svsk->sk_server->sv_name, -len); - svc_sock_received(svsk, 0); + svc_sock_received(svsk); } return len; @@ -737,8 +869,6 @@ /* * Send out data on TCP socket. - * FIXME: Make the sendto call non-blocking in order not to hang - * a daemon on a dead client. Requires write queue maintenance. */ static int svc_tcp_sendto(struct svc_rqst *rqstp) @@ -759,10 +889,8 @@ printk(KERN_NOTICE "rpc-srv/tcp: %s: sent only %d bytes of %d - should shutdown socket\n", rqstp->rq_sock->sk_server->sv_name, sent, bufp->len << 2); - /* FIXME: should shutdown the socket, or allocate more memort - * or wait and try again or something. Otherwise - * client will get confused - */ + svc_delete_socket(rqstp->rq_sock); + sent = -EAGAIN; } return sent; } @@ -782,21 +910,77 @@ dprintk("setting up TCP socket for reading\n"); sk->state_change = svc_tcp_state_change; sk->data_ready = svc_tcp_data_ready; + sk->write_space = svc_write_space; svsk->sk_reclen = 0; svsk->sk_tcplen = 0; + + /* sndbuf needs to have room for one request + * per thread, otherwise we can stall even when the + * network isn't a bottleneck. + * rcvbuf just needs to be able to hold a few requests. + * Normally they will be removed from the queue + * as soon a a complete request arrives. + */ + svc_sock_setbufsize(svsk->sk_sock, + svsk->sk_server->sv_nrthreads * + svsk->sk_server->sv_bufsz, + 3 * svsk->sk_server->sv_bufsz); } return 0; } +void +svc_sock_update_bufs(struct svc_serv *serv) +{ + /* + * The number of server threads has changed. Update + * rcvbuf and sndbuf accordingly on all sockets + */ + struct list_head *le; + + spin_lock_bh(&serv->sv_lock); + list_for_each(le, &serv->sv_permsocks) { + struct svc_sock *svsk = + list_entry(le, struct svc_sock, sk_list); + struct socket *sock = svsk->sk_sock; + if (sock->type == SOCK_DGRAM) { + /* udp sockets need large rcvbuf as all pending + * requests are still in that buffer. + * As outgoing requests do not wait for an + * ACK, only a moderate sndbuf is needed + */ + svc_sock_setbufsize(sock, + 5 * serv->sv_bufsz, + (serv->sv_nrthreads+2)* serv->sv_bufsz); + } else if (svsk->sk_sk->state != TCP_LISTEN) { + printk(KERN_ERR "RPC update_bufs: permanent sock neither UDP or TCP_LISTEN\n"); + } + } + list_for_each(le, &serv->sv_tempsocks) { + struct svc_sock *svsk = + list_entry(le, struct svc_sock, sk_list); + struct socket *sock = svsk->sk_sock; + if (sock->type == SOCK_STREAM) { + /* See svc_tcp_init above for rationale on buffer sizes */ + svc_sock_setbufsize(sock, + serv->sv_nrthreads * + serv->sv_bufsz, + 3 * serv->sv_bufsz); + } else + printk(KERN_ERR "RPC update_bufs: temp sock not TCP\n"); + } + spin_unlock_bh(&serv->sv_lock); +} + /* * Receive the next request on any socket. */ int svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) { - struct svc_sock *svsk; + struct svc_sock *svsk =NULL; int len; DECLARE_WAITQUEUE(wait, current); @@ -820,9 +1004,28 @@ return -EINTR; spin_lock_bh(&serv->sv_lock); - if ((svsk = svc_sock_dequeue(serv)) != NULL) { + if (!list_empty(&serv->sv_tempsocks)) { + svsk = list_entry(serv->sv_tempsocks.next, + struct svc_sock, sk_list); + /* apparently the "standard" is that clients close + * idle connections after 5 minutes, servers after + * 6 minutes + * http://www.connectathon.org/talks96/nfstcp.pdf + */ + if (CURRENT_TIME - svsk->sk_lastrecv < 6*60 + || test_bit(SK_BUSY, &svsk->sk_flags)) + svsk = NULL; + } + if (svsk) { + set_bit(SK_BUSY, &svsk->sk_flags); + set_bit(SK_CLOSE, &svsk->sk_flags); + rqstp->rq_sock = svsk; + svsk->sk_inuse++; + } else if ((svsk = svc_sock_dequeue(serv)) != NULL) { rqstp->rq_sock = svsk; svsk->sk_inuse++; + rqstp->rq_reserved = serv->sv_bufsz; + svsk->sk_reserved += rqstp->rq_reserved; } else { /* No data pending. Go to sleep */ svc_serv_enqueue(serv, rqstp); @@ -859,6 +1062,14 @@ svc_sock_release(rqstp); return -EAGAIN; } + svsk->sk_lastrecv = CURRENT_TIME; + if (test_bit(SK_TEMP, &svsk->sk_flags)) { + /* push active sockets to end of list */ + spin_lock_bh(&serv->sv_lock); + list_del(&svsk->sk_list); + list_add_tail(&svsk->sk_list, &serv->sv_tempsocks); + spin_unlock_bh(&serv->sv_lock); + } rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024; rqstp->rq_userset = 0; @@ -935,8 +1146,9 @@ svsk->sk_sk = inet; svsk->sk_ostate = inet->state_change; svsk->sk_odata = inet->data_ready; + svsk->sk_owspace = inet->write_space; svsk->sk_server = serv; - spin_lock_init(&svsk->sk_lock); + svsk->sk_lastrecv = CURRENT_TIME; /* Initialize the socket */ if (sock->type == SOCK_DGRAM) @@ -956,9 +1168,16 @@ return NULL; } + spin_lock_bh(&serv->sv_lock); - svsk->sk_list = serv->sv_allsocks; - serv->sv_allsocks = svsk; + if (!pmap_register) { + set_bit(SK_TEMP, &svsk->sk_flags); + list_add(&svsk->sk_list, &serv->sv_tempsocks); + serv->sv_tmpcnt++; + } else { + clear_bit(SK_TEMP, &svsk->sk_flags); + list_add(&svsk->sk_list, &serv->sv_permsocks); + } spin_unlock_bh(&serv->sv_lock); dprintk("svc: svc_setup_socket created %p (inet %p)\n", @@ -1019,7 +1238,6 @@ void svc_delete_socket(struct svc_sock *svsk) { - struct svc_sock **rsk; struct svc_serv *serv; struct sock *sk; @@ -1030,23 +1248,18 @@ sk->state_change = svsk->sk_ostate; sk->data_ready = svsk->sk_odata; + sk->write_space = svsk->sk_owspace; spin_lock_bh(&serv->sv_lock); - for (rsk = &serv->sv_allsocks; *rsk; rsk = &(*rsk)->sk_list) { - if (*rsk == svsk) - break; - } - if (!*rsk) { - spin_unlock_bh(&serv->sv_lock); - return; - } - *rsk = svsk->sk_list; - if (svsk->sk_qued) - rpc_remove_list(&serv->sv_sockets, svsk); + list_del(&svsk->sk_list); + if (test_bit(SK_TEMP, &svsk->sk_flags)) + serv->sv_tmpcnt--; + if (test_bit(SK_QUED, &svsk->sk_flags)) + list_del(&svsk->sk_ready); - svsk->sk_dead = 1; + set_bit(SK_DEAD, &svsk->sk_flags); if (!svsk->sk_inuse) { spin_unlock_bh(&serv->sv_lock); diff -u --recursive --new-file linux-2.4.19-fix_lockd4/net/sunrpc/xprt.c linux-2.4.19-neilb/net/sunrpc/xprt.c --- linux-2.4.19-fix_lockd4/net/sunrpc/xprt.c Thu Aug 1 12:24:30 2002 +++ linux-2.4.19-neilb/net/sunrpc/xprt.c Thu Aug 1 12:36:27 2002 @@ -1328,10 +1328,10 @@ } else xprt_default_timeout(&xprt->timeout, xprt->prot); - xprt->pending = RPC_INIT_WAITQ("xprt_pending"); - xprt->sending = RPC_INIT_WAITQ("xprt_sending"); - xprt->resend = RPC_INIT_WAITQ("xprt_resend"); - xprt->backlog = RPC_INIT_WAITQ("xprt_backlog"); + INIT_RPC_WAITQ(&xprt->pending, "xprt_pending"); + INIT_RPC_WAITQ(&xprt->sending, "xprt_sending"); + INIT_RPC_WAITQ(&xprt->resend, "xprt_resend"); + INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog"); /* initialize free list */ for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++)