fs/nfs/direct.c | 219 +++++++++++-- fs/nfs/file.c | 20 + fs/nfs/inode.c | 110 ++++-- fs/nfs/nfs2xdr.c | 11 fs/nfs/nfs3proc.c | 50 --- fs/nfs/nfs3xdr.c | 11 fs/nfs/nfs4proc.c | 179 +++-------- fs/nfs/nfs4state.c | 2 fs/nfs/nfs4xdr.c | 54 +-- fs/nfs/pagelist.c | 47 +- fs/nfs/proc.c | 46 -- fs/nfs/read.c | 63 ++- fs/nfs/unlink.c | 3 fs/nfs/write.c | 93 ++--- include/linux/nfs_fs.h | 41 +- include/linux/nfs_page.h | 29 - include/linux/nfs_xdr.h | 22 - include/linux/sunrpc/gss_api.h | 70 +--- include/linux/sunrpc/gss_asn1.h | 3 include/linux/sunrpc/gss_krb5.h | 2 include/linux/sunrpc/sched.h | 55 ++- include/linux/sunrpc/xprt.h | 10 net/sunrpc/auth_gss/Makefile | 6 net/sunrpc/auth_gss/auth_gss.c | 235 ++++++++------ net/sunrpc/auth_gss/gss_generic_token.c | 15 net/sunrpc/auth_gss/gss_krb5_crypto.c | 31 + net/sunrpc/auth_gss/gss_krb5_mech.c | 40 +- net/sunrpc/auth_gss/gss_krb5_seal.c | 15 net/sunrpc/auth_gss/gss_krb5_seqnum.c | 2 net/sunrpc/auth_gss/gss_krb5_unseal.c | 8 net/sunrpc/auth_gss/gss_mech_switch.c | 211 +++++++------ net/sunrpc/auth_gss/gss_pseudoflavors.c | 236 -------------- net/sunrpc/auth_gss/sunrpcgss_syms.c | 35 -- net/sunrpc/auth_gss/svcauth_gss.c | 36 +- net/sunrpc/clnt.c | 8 net/sunrpc/sched.c | 510 +++++++++----------------------- net/sunrpc/timer.c | 1 net/sunrpc/xprt.c | 97 +++--- 38 files changed, 1184 insertions(+), 1442 deletions(-) diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/direct.c linux-2.6.6-18-file_ctx2/fs/nfs/direct.c --- linux-2.6.6/fs/nfs/direct.c 2004-05-09 22:33:19.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/direct.c 2004-05-17 15:17:25.000000000 -0400 @@ -32,6 +32,7 @@ * 18 Dec 2001 Initial implementation for 2.4 --cel * 08 Jul 2002 Version for 2.4.19, with bug fixes --trondmy * 08 Jun 2003 Port to 2.5 APIs --cel + * 31 Mar 2004 Handle direct I/O without VFS support --cel * */ @@ -109,7 +110,7 @@ nfs_free_user_pages(struct page **pages, * nfs_direct_read_seg - Read in one iov segment. Generate separate * read RPCs for each "rsize" bytes. * @inode: target inode - * @file: target file (may be NULL) + * @ctx: target file open context * user_addr: starting address of this segment of user's buffer * count: size of this segment * file_offset: offset in file to begin the operation @@ -117,7 +118,7 @@ nfs_free_user_pages(struct page **pages, * nr_pages: size of pages array */ static int -nfs_direct_read_seg(struct inode *inode, struct file *file, +nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx, unsigned long user_addr, size_t count, loff_t file_offset, struct page **pages, int nr_pages) { @@ -126,9 +127,10 @@ nfs_direct_read_seg(struct inode *inode, int curpage = 0; struct nfs_read_data rdata = { .inode = inode, + .cred = ctx->cred, .args = { .fh = NFS_FH(inode), - .lockowner = current->files, + .context = ctx, }, .res = { .fattr = &rdata.fattr, @@ -150,7 +152,7 @@ nfs_direct_read_seg(struct inode *inode, user_addr + tot_bytes, rdata.args.pgbase, curpage); lock_kernel(); - result = NFS_PROTO(inode)->read(&rdata, file); + result = NFS_PROTO(inode)->read(&rdata); unlock_kernel(); if (result <= 0) { @@ -182,7 +184,7 @@ nfs_direct_read_seg(struct inode *inode, * nfs_direct_read - For each iov segment, map the user's buffer * then generate read RPCs. * @inode: target inode - * @file: target file (may be NULL) + * @ctx: target file open context * @iov: array of vectors that define I/O buffer * file_offset: offset in file to begin the operation * nr_segs: size of iovec array @@ -192,7 +194,7 @@ nfs_direct_read_seg(struct inode *inode, * server. */ static ssize_t -nfs_direct_read(struct inode *inode, struct file *file, +nfs_direct_read(struct inode *inode, struct nfs_open_context *ctx, const struct iovec *iov, loff_t file_offset, unsigned long nr_segs) { @@ -215,7 +217,7 @@ nfs_direct_read(struct inode *inode, str return page_count; } - result = nfs_direct_read_seg(inode, file, user_addr, size, + result = nfs_direct_read_seg(inode, ctx, user_addr, size, file_offset, pages, page_count); nfs_free_user_pages(pages, page_count, 1); @@ -238,7 +240,7 @@ nfs_direct_read(struct inode *inode, str * nfs_direct_write_seg - Write out one iov segment. Generate separate * write RPCs for each "wsize" bytes, then commit. * @inode: target inode - * @file: target file (may be NULL) + * @ctx: target file open context * user_addr: starting address of this segment of user's buffer * count: size of this segment * file_offset: offset in file to begin the operation @@ -246,7 +248,7 @@ nfs_direct_read(struct inode *inode, str * nr_pages: size of pages array */ static int -nfs_direct_write_seg(struct inode *inode, struct file *file, +nfs_direct_write_seg(struct inode *inode, struct nfs_open_context *ctx, unsigned long user_addr, size_t count, loff_t file_offset, struct page **pages, int nr_pages) { @@ -258,9 +260,10 @@ nfs_direct_write_seg(struct inode *inode struct nfs_writeverf first_verf; struct nfs_write_data wdata = { .inode = inode, + .cred = ctx->cred, .args = { .fh = NFS_FH(inode), - .lockowner = current->files, + .context = ctx, }, .res = { .fattr = &wdata.fattr, @@ -293,13 +296,13 @@ retry: user_addr + tot_bytes, wdata.args.pgbase, curpage); lock_kernel(); - result = NFS_PROTO(inode)->write(&wdata, file); + result = NFS_PROTO(inode)->write(&wdata); unlock_kernel(); if (result <= 0) { if (tot_bytes > 0) break; - return result; + goto out; } if (tot_bytes == 0) @@ -330,7 +333,7 @@ retry: wdata.args.offset = file_offset; lock_kernel(); - result = NFS_PROTO(inode)->commit(&wdata, file); + result = NFS_PROTO(inode)->commit(&wdata); unlock_kernel(); if (result < 0 || memcmp(&first_verf.verifier, @@ -338,9 +341,12 @@ retry: VERF_SIZE) != 0) goto sync_retry; } + result = tot_bytes; + +out: nfs_end_data_update_defer(inode); - return tot_bytes; + return result; sync_retry: wdata.args.stable = NFS_FILE_SYNC; @@ -351,7 +357,7 @@ sync_retry: * nfs_direct_write - For each iov segment, map the user's buffer * then generate write and commit RPCs. * @inode: target inode - * @file: target file (may be NULL) + * @ctx: target file open context * @iov: array of vectors that define I/O buffer * file_offset: offset in file to begin the operation * nr_segs: size of iovec array @@ -360,8 +366,7 @@ sync_retry: * that non-direct readers might access, so they will pick up these * writes immediately. */ -static ssize_t -nfs_direct_write(struct inode *inode, struct file *file, +static int nfs_direct_write(struct inode *inode, struct nfs_open_context *ctx, const struct iovec *iov, loff_t file_offset, unsigned long nr_segs) { @@ -384,7 +389,7 @@ nfs_direct_write(struct inode *inode, st return page_count; } - result = nfs_direct_write_seg(inode, file, user_addr, size, + result = nfs_direct_write_seg(inode, ctx, user_addr, size, file_offset, pages, page_count); nfs_free_user_pages(pages, page_count, 0); @@ -409,12 +414,6 @@ nfs_direct_write(struct inode *inode, st * file_offset: offset in file to begin the operation * nr_segs: size of iovec array * - * Usually a file system implements direct I/O by calling out to - * blockdev_direct_IO. The NFS client doesn't have a backing block - * device, so we do everything by hand instead. - * - * The inode's i_sem is no longer held by the VFS layer before it calls - * this function to do a write. */ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, @@ -422,6 +421,7 @@ nfs_direct_IO(int rw, struct kiocb *iocb { ssize_t result = -EINVAL; struct file *file = iocb->ki_filp; + struct nfs_open_context *ctx; struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; @@ -429,32 +429,185 @@ nfs_direct_IO(int rw, struct kiocb *iocb * No support for async yet */ if (!is_sync_kiocb(iocb)) - goto out; - - result = nfs_revalidate_inode(NFS_SERVER(inode), inode); - if (result < 0) - goto out; + return result; + ctx = (struct nfs_open_context *)file->private_data; switch (rw) { case READ: dprintk("NFS: direct_IO(read) (%s) off/no(%Lu/%lu)\n", dentry->d_name.name, file_offset, nr_segs); - result = nfs_direct_read(inode, file, iov, + result = nfs_direct_read(inode, ctx, iov, file_offset, nr_segs); break; case WRITE: dprintk("NFS: direct_IO(write) (%s) off/no(%Lu/%lu)\n", dentry->d_name.name, file_offset, nr_segs); - result = nfs_direct_write(inode, file, iov, + result = nfs_direct_write(inode, ctx, iov, file_offset, nr_segs); break; default: break; } + return result; +} + +/** + * nfs_file_direct_read - file direct read operation for NFS files + * @iocb: target I/O control block + * @buf: user's buffer into which to read data + * count: number of bytes to read + * pos: byte offset in file where reading starts + * + * We use this function for direct reads instead of calling + * generic_file_aio_read() in order to avoid gfar's check to see if + * the request starts before the end of the file. For that check + * to work, we must generate a GETATTR before each direct read, and + * even then there is a window between the GETATTR and the subsequent + * READ where the file size could change. So our preference is simply + * to do all reads the application wants, and the server will take + * care of managing the end of file boundary. + * + * This function also eliminates unnecessarily updating the file's + * atime locally, as the NFS server sets the file's atime, and this + * client must read the updated atime from the server back into its + * cache. + */ +ssize_t +nfs_file_direct_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos) +{ + ssize_t retval = -EINVAL; + loff_t *ppos = &iocb->ki_pos; + struct file *file = iocb->ki_filp; + struct nfs_open_context *ctx = + (struct nfs_open_context *) file->private_data; + struct dentry *dentry = file->f_dentry; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + struct iovec iov = { + .iov_base = buf, + .iov_len = count, + }; + + dprintk("nfs: direct read(%s/%s, %lu@%lu)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + (unsigned long) count, (unsigned long) pos); + + if (!is_sync_kiocb(iocb)) + goto out; + if (count < 0) + goto out; + retval = -EFAULT; + if (!access_ok(VERIFY_WRITE, iov.iov_base, iov.iov_len)) + goto out; + retval = 0; + if (!count) + goto out; + + if (mapping->nrpages) { + retval = filemap_fdatawrite(mapping); + if (retval == 0) + retval = filemap_fdatawait(mapping); + if (retval) + goto out; + } + + retval = nfs_direct_read(inode, ctx, &iov, pos, 1); + if (retval > 0) + *ppos = pos + retval; out: - dprintk("NFS: direct_IO result=%zd\n", result); - return result; + return retval; +} + +/** + * nfs_file_direct_write - file direct write operation for NFS files + * @iocb: target I/O control block + * @buf: user's buffer from which to write data + * count: number of bytes to write + * pos: byte offset in file where writing starts + * + * We use this function for direct writes instead of calling + * generic_file_aio_write() in order to avoid taking the inode + * semaphore and updating the i_size. The NFS server will set + * the new i_size and this client must read the updated size + * back into its cache. We let the server do generic write + * parameter checking and report problems. + * + * We also avoid an unnecessary invocation of generic_osync_inode(), + * as it is fairly meaningless to sync the metadata of an NFS file. + * + * We eliminate local atime updates, see direct read above. + * + * We avoid unnecessary page cache invalidations for normal cached + * readers of this file. + * + * Note that O_APPEND is not supported for NFS direct writes, as there + * is no atomic O_APPEND write facility in the NFS protocol. + */ +ssize_t +nfs_file_direct_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos) +{ + ssize_t retval = -EINVAL; + loff_t *ppos = &iocb->ki_pos; + unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + struct file *file = iocb->ki_filp; + struct nfs_open_context *ctx = + (struct nfs_open_context *) file->private_data; + struct dentry *dentry = file->f_dentry; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + struct iovec iov = { + .iov_base = (void __user *)buf, + .iov_len = count, + }; + + dfprintk(VFS, "nfs: direct write(%s/%s(%ld), %lu@%lu)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + inode->i_ino, (unsigned long) count, (unsigned long) pos); + + if (!is_sync_kiocb(iocb)) + goto out; + if (count < 0) + goto out; + if (pos < 0) + goto out; + retval = -EFAULT; + if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) + goto out; + if (file->f_error) { + retval = file->f_error; + file->f_error = 0; + goto out; + } + retval = -EFBIG; + if (limit != RLIM_INFINITY) { + if (pos >= limit) { + send_sig(SIGXFSZ, current, 0); + goto out; + } + if (count > limit - (unsigned long) pos) + count = limit - (unsigned long) pos; + } + retval = 0; + if (!count) + goto out; + + if (mapping->nrpages) { + retval = filemap_fdatawrite(mapping); + if (retval == 0) + retval = filemap_fdatawait(mapping); + if (retval) + goto out; + } + + retval = nfs_direct_write(inode, ctx, &iov, pos, 1); + if (mapping->nrpages) + invalidate_inode_pages2(mapping); + if (retval > 0) + *ppos = pos + retval; + +out: + return retval; } diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/file.c linux-2.6.6-18-file_ctx2/fs/nfs/file.c --- linux-2.6.6/fs/nfs/file.c 2004-05-09 22:32:52.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/file.c 2004-05-17 15:17:17.000000000 -0400 @@ -127,6 +127,7 @@ nfs_file_release(struct inode *inode, st static int nfs_file_flush(struct file *file) { + struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; struct inode *inode = file->f_dentry->d_inode; int status; @@ -138,8 +139,8 @@ nfs_file_flush(struct file *file) /* Ensure that data+attribute caches are up to date after close() */ status = nfs_wb_all(inode); if (!status) { - status = file->f_error; - file->f_error = 0; + status = ctx->error; + ctx->error = 0; if (!status) __nfs_revalidate_inode(NFS_SERVER(inode), inode); } @@ -154,6 +155,11 @@ nfs_file_read(struct kiocb *iocb, char * struct inode * inode = dentry->d_inode; ssize_t result; +#ifdef CONFIG_NFS_DIRECTIO + if (iocb->ki_filp->f_flags & O_DIRECT) + return nfs_file_direct_read(iocb, buf, count, pos); +#endif + dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", dentry->d_parent->d_name.name, dentry->d_name.name, (unsigned long) count, (unsigned long) pos); @@ -206,6 +212,7 @@ nfs_file_mmap(struct file * file, struct static int nfs_fsync(struct file *file, struct dentry *dentry, int datasync) { + struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; struct inode *inode = dentry->d_inode; int status; @@ -214,8 +221,8 @@ nfs_fsync(struct file *file, struct dent lock_kernel(); status = nfs_wb_all(inode); if (!status) { - status = file->f_error; - file->f_error = 0; + status = ctx->error; + ctx->error = 0; } unlock_kernel(); return status; @@ -268,6 +275,11 @@ nfs_file_write(struct kiocb *iocb, const struct inode * inode = dentry->d_inode; ssize_t result; +#ifdef CONFIG_NFS_DIRECTIO + if (iocb->ki_filp->f_flags & O_DIRECT) + return nfs_file_direct_write(iocb, buf, count, pos); +#endif + dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%lu)\n", dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, (unsigned long) count, (unsigned long) pos); diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/inode.c linux-2.6.6-18-file_ctx2/fs/nfs/inode.c --- linux-2.6.6/fs/nfs/inode.c 2004-05-09 22:33:12.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/inode.c 2004-05-17 15:17:17.000000000 -0400 @@ -123,8 +123,9 @@ nfs_delete_inode(struct inode * inode) { dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); + nfs_wb_all(inode); /* - * The following can never actually happen... + * The following should never happen... */ if (nfs_have_writebacks(inode)) { printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino); @@ -141,10 +142,12 @@ static void nfs_clear_inode(struct inode *inode) { struct nfs_inode *nfsi = NFS_I(inode); - struct rpc_cred *cred = nfsi->mm_cred; + struct nfs_open_context *ctx = nfsi->mm_context; + struct rpc_cred *cred; - if (cred) - put_rpccred(cred); + nfs_wb_all(inode); + if (ctx != NULL) + put_nfs_open_context(ctx); cred = nfsi->cache_access.cred; if (cred) put_rpccred(cred); @@ -237,7 +240,7 @@ nfs_get_root(struct super_block *sb, str error = server->rpc_ops->getroot(server, rootfh, fsinfo); if (error < 0) { - printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error); + dprintk("nfs_get_root: getattr error = %d\n", -error); return ERR_PTR(error); } @@ -262,6 +265,7 @@ nfs_sb_init(struct super_block *sb, rpc_ struct nfs_pathconf pathinfo = { .fattr = &fattr, }; + int no_root_error = 0; /* We probably want something more informative here */ snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); @@ -272,12 +276,15 @@ nfs_sb_init(struct super_block *sb, rpc_ root_inode = nfs_get_root(sb, &server->fh, &fsinfo); /* Did getting the root inode fail? */ - if (IS_ERR(root_inode)) + if (IS_ERR(root_inode)) { + no_root_error = PTR_ERR(root_inode); goto out_no_root; + } sb->s_root = d_alloc_root(root_inode); - if (!sb->s_root) + if (!sb->s_root) { + no_root_error = -ENOMEM; goto out_no_root; - + } sb->s_root->d_op = server->rpc_ops->dentry_ops; /* Get some general file system info */ @@ -337,10 +344,10 @@ nfs_sb_init(struct super_block *sb, rpc_ return 0; /* Yargs. It didn't work out. */ out_no_root: - printk("nfs_read_super: get root inode failed\n"); + dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error); if (!IS_ERR(root_inode)) iput(root_inode); - return -EINVAL; + return no_root_error; } /* @@ -855,37 +862,74 @@ int nfs_getattr(struct vfsmount *mnt, st return err; } +struct nfs_open_context *alloc_nfs_open_context(struct inode *inode, struct rpc_cred *cred) +{ + struct nfs_open_context *ctx; + + ctx = (struct nfs_open_context *)kmalloc(sizeof(*ctx), GFP_KERNEL); + if (ctx != NULL) { + atomic_set(&ctx->count, 1); + ctx->inode = inode; + ctx->cred = get_rpccred(cred); + ctx->state = NULL; + ctx->lockowner = current->files; + ctx->error = 0; + init_waitqueue_head(&ctx->waitq); + } + return ctx; +} + +struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) +{ + if (ctx != NULL) + atomic_inc(&ctx->count); + return ctx; +} + +void put_nfs_open_context(struct nfs_open_context *ctx) +{ + if (atomic_dec_and_test(&ctx->count)) { + if (ctx->state != NULL) + nfs4_put_open_state(ctx->state); + if (ctx->cred != NULL) + put_rpccred(ctx->cred); + kfree(ctx); + } +} + /* * Ensure that mmap has a recent RPC credential for use when writing out * shared pages */ -void -nfs_set_mmcred(struct inode *inode, struct rpc_cred *cred) +void nfs_set_mmcontext(struct inode *inode, struct nfs_open_context *ctx) { - struct rpc_cred **p = &NFS_I(inode)->mm_cred, - *oldcred = *p; + struct nfs_open_context **p = &NFS_I(inode)->mm_context, + *old = *p; - *p = get_rpccred(cred); - if (oldcred) - put_rpccred(oldcred); + *p = get_nfs_open_context(ctx); + if (old) + put_nfs_open_context(old); } /* - * These are probably going to contain hooks for - * allocating and releasing RPC credentials for - * the file. I'll have to think about Tronds patch - * a bit more.. + * These allocate and release file read/write context information. */ int nfs_open(struct inode *inode, struct file *filp) { - struct rpc_auth *auth; + struct nfs_open_context *ctx; struct rpc_cred *cred; - auth = NFS_CLIENT(inode)->cl_auth; - cred = rpcauth_lookupcred(auth, 0); - filp->private_data = cred; + if ((cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0)) == NULL) + return -ENOMEM; + ctx = alloc_nfs_open_context(inode, cred); + put_rpccred(cred); + if (ctx == NULL) + return -ENOMEM; + filp->private_data = ctx; if ((filp->f_mode & FMODE_WRITE) != 0) { - nfs_set_mmcred(inode, cred); + lock_kernel(); + nfs_set_mmcontext(inode, ctx); + unlock_kernel(); nfs_begin_data_update(inode); } return 0; @@ -893,14 +937,13 @@ int nfs_open(struct inode *inode, struct int nfs_release(struct inode *inode, struct file *filp) { - struct rpc_cred *cred; + struct nfs_open_context *ctx; lock_kernel(); if ((filp->f_mode & FMODE_WRITE) != 0) nfs_end_data_update(inode); - cred = nfs_file_cred(filp); - if (cred) - put_rpccred(cred); + if ((ctx = (struct nfs_open_context *)filp->private_data) != NULL) + put_nfs_open_context(ctx); unlock_kernel(); return 0; } @@ -1419,6 +1462,9 @@ static void nfs4_clear_inode(struct inod { struct nfs_inode *nfsi = NFS_I(inode); + /* First call standard NFS clear_inode() code */ + nfs_clear_inode(inode); + /* Now clear out any remaining state */ while (!list_empty(&nfsi->open_states)) { struct nfs4_state *state; @@ -1433,8 +1479,6 @@ static void nfs4_clear_inode(struct inod BUG_ON(atomic_read(&state->count) != 1); nfs4_close_state(state, state->state); } - /* Now call standard NFS clear_inode() code */ - nfs_clear_inode(inode); } @@ -1742,7 +1786,7 @@ static struct inode *nfs_alloc_inode(str if (!nfsi) return NULL; nfsi->flags = 0; - nfsi->mm_cred = NULL; + nfsi->mm_context = NULL; nfs4_zero_state(nfsi); return &nfsi->vfs_inode; } diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/nfs2xdr.c linux-2.6.6-18-file_ctx2/fs/nfs/nfs2xdr.c --- linux-2.6.6/fs/nfs/nfs2xdr.c 2004-05-09 22:32:28.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/nfs2xdr.c 2004-05-17 15:15:33.000000000 -0400 @@ -511,8 +511,8 @@ static int nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; + unsigned int count = args->count - 5; unsigned int replen; - u32 count = args->count - 4; p = xdr_encode_fhandle(p, args->fh); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); @@ -547,12 +547,15 @@ nfs_xdr_readlinkres(struct rpc_rqst *req strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0); /* Convert length of symlink */ len = ntohl(*strlen); - if (len > rcvbuf->page_len) - len = rcvbuf->page_len; + if (len > rcvbuf->page_len) { + dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); + kunmap_atomic(strlen, KM_USER0); + return -ENAMETOOLONG; + } *strlen = len; /* NULL terminate the string we got */ string = (char *)(strlen + 1); - string[len] = 0; + string[len] = '\0'; kunmap_atomic(strlen, KM_USER0); return 0; } diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/nfs3proc.c linux-2.6.6-18-file_ctx2/fs/nfs/nfs3proc.c --- linux-2.6.6/fs/nfs/nfs3proc.c 2004-05-09 22:32:36.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/nfs3proc.c 2004-05-17 15:17:17.000000000 -0400 @@ -68,18 +68,6 @@ nfs3_async_handle_jukebox(struct rpc_tas return 1; } -static struct rpc_cred * -nfs_cred(struct inode *inode, struct file *filp) -{ - struct rpc_cred *cred = NULL; - - if (filp) - cred = (struct rpc_cred *)filp->private_data; - if (!cred) - cred = NFS_I(inode)->mm_cred; - return cred; -} - /* * Bare-bones access to getattr: this is for nfs_read_super. */ @@ -227,8 +215,7 @@ nfs3_proc_readlink(struct inode *inode, return status; } -static int -nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp) +static int nfs3_proc_read(struct nfs_read_data *rdata) { int flags = rdata->flags; struct inode * inode = rdata->inode; @@ -237,13 +224,13 @@ nfs3_proc_read(struct nfs_read_data *rda .rpc_proc = &nfs3_procedures[NFS3PROC_READ], .rpc_argp = &rdata->args, .rpc_resp = &rdata->res, + .rpc_cred = rdata->cred, }; int status; dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); fattr->valid = 0; - msg.rpc_cred = nfs_cred(inode, filp); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) nfs_refresh_inode(inode, fattr); @@ -251,8 +238,7 @@ nfs3_proc_read(struct nfs_read_data *rda return status; } -static int -nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp) +static int nfs3_proc_write(struct nfs_write_data *wdata) { int rpcflags = wdata->flags; struct inode * inode = wdata->inode; @@ -261,13 +247,13 @@ nfs3_proc_write(struct nfs_write_data *w .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], .rpc_argp = &wdata->args, .rpc_resp = &wdata->res, + .rpc_cred = wdata->cred, }; int status; dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); fattr->valid = 0; - msg.rpc_cred = nfs_cred(inode, filp); status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); if (status >= 0) nfs_refresh_inode(inode, fattr); @@ -275,8 +261,7 @@ nfs3_proc_write(struct nfs_write_data *w return status < 0? status : wdata->res.count; } -static int -nfs3_proc_commit(struct nfs_write_data *cdata, struct file *filp) +static int nfs3_proc_commit(struct nfs_write_data *cdata) { struct inode * inode = cdata->inode; struct nfs_fattr * fattr = cdata->res.fattr; @@ -284,13 +269,13 @@ nfs3_proc_commit(struct nfs_write_data * .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], .rpc_argp = &cdata->args, .rpc_resp = &cdata->res, + .rpc_cred = cdata->cred, }; int status; dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, (long long) cdata->args.offset); fattr->valid = 0; - msg.rpc_cred = nfs_cred(inode, filp); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (status >= 0) nfs_refresh_inode(inode, fattr); @@ -832,27 +817,6 @@ nfs3_proc_commit_setup(struct nfs_write_ rpc_call_setup(task, &msg, 0); } -/* - * Set up the nfspage struct with the right credentials - */ -void -nfs3_request_init(struct nfs_page *req, struct file *filp) -{ - req->wb_cred = get_rpccred(nfs_cred(req->wb_inode, filp)); -} - -static int -nfs3_request_compatible(struct nfs_page *req, struct file *filp, struct page *page) -{ - if (req->wb_file != filp) - return 0; - if (req->wb_page != page) - return 0; - if (req->wb_cred != nfs_file_cred(filp)) - return 0; - return 1; -} - static int nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) { @@ -892,7 +856,5 @@ struct nfs_rpc_ops nfs_v3_clientops = { .commit_setup = nfs3_proc_commit_setup, .file_open = nfs_open, .file_release = nfs_release, - .request_init = nfs3_request_init, - .request_compatible = nfs3_request_compatible, .lock = nfs3_proc_lock, }; diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/nfs3xdr.c linux-2.6.6-18-file_ctx2/fs/nfs/nfs3xdr.c --- linux-2.6.6/fs/nfs/nfs3xdr.c 2004-05-09 22:33:21.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/nfs3xdr.c 2004-05-17 15:15:33.000000000 -0400 @@ -702,8 +702,8 @@ static int nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; + unsigned int count = args->count - 5; unsigned int replen; - u32 count = args->count - 4; p = xdr_encode_fhandle(p, args->fh); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); @@ -742,12 +742,15 @@ nfs3_xdr_readlinkres(struct rpc_rqst *re strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0); /* Convert length of symlink */ len = ntohl(*strlen); - if (len > rcvbuf->page_len) - len = rcvbuf->page_len; + if (len > rcvbuf->page_len) { + dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); + kunmap_atomic(strlen, KM_USER0); + return -ENAMETOOLONG; + } *strlen = len; /* NULL terminate the string we got */ string = (char *)(strlen + 1); - string[len] = 0; + string[len] = '\0'; kunmap_atomic(strlen, KM_USER0); return 0; } diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/nfs4proc.c linux-2.6.6-18-file_ctx2/fs/nfs/nfs4proc.c --- linux-2.6.6/fs/nfs/nfs4proc.c 2004-05-09 22:32:54.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/nfs4proc.c 2004-05-17 15:17:17.000000000 -0400 @@ -816,8 +816,7 @@ static int nfs4_proc_readlink(struct ino return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0)); } -static int -nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp) +static int nfs4_proc_read(struct nfs_read_data *rdata) { int flags = rdata->flags; struct inode *inode = rdata->inode; @@ -827,6 +826,7 @@ nfs4_proc_read(struct nfs_read_data *rda .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ], .rpc_argp = &rdata->args, .rpc_resp = &rdata->res, + .rpc_cred = rdata->cred, }; unsigned long timestamp = jiffies; int status; @@ -834,19 +834,6 @@ nfs4_proc_read(struct nfs_read_data *rda dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); - /* - * Try first to use O_RDONLY, then O_RDWR stateid. - */ - if (filp) { - struct nfs4_state *state; - state = (struct nfs4_state *)filp->private_data; - rdata->args.state = state; - msg.rpc_cred = state->owner->so_cred; - } else { - rdata->args.state = NULL; - msg.rpc_cred = NFS_I(inode)->mm_cred; - } - fattr->valid = 0; status = rpc_call_sync(server->client, &msg, flags); if (!status) @@ -855,8 +842,7 @@ nfs4_proc_read(struct nfs_read_data *rda return nfs4_map_errors(status); } -static int -nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp) +static int nfs4_proc_write(struct nfs_write_data *wdata) { int rpcflags = wdata->flags; struct inode *inode = wdata->inode; @@ -866,33 +852,20 @@ nfs4_proc_write(struct nfs_write_data *w .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], .rpc_argp = &wdata->args, .rpc_resp = &wdata->res, + .rpc_cred = wdata->cred, }; int status; dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); - /* - * Try first to use O_WRONLY, then O_RDWR stateid. - */ - if (filp) { - struct nfs4_state *state; - state = (struct nfs4_state *)filp->private_data; - wdata->args.state = state; - msg.rpc_cred = state->owner->so_cred; - } else { - wdata->args.state = NULL; - msg.rpc_cred = NFS_I(inode)->mm_cred; - } - fattr->valid = 0; status = rpc_call_sync(server->client, &msg, rpcflags); dprintk("NFS reply write: %d\n", status); return nfs4_map_errors(status); } -static int -nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp) +static int nfs4_proc_commit(struct nfs_write_data *cdata) { struct inode *inode = cdata->inode; struct nfs_fattr *fattr = cdata->res.fattr; @@ -901,20 +874,13 @@ nfs4_proc_commit(struct nfs_write_data * .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], .rpc_argp = &cdata->args, .rpc_resp = &cdata->res, + .rpc_cred = cdata->cred, }; int status; dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, (long long) cdata->args.offset); - /* - * Try first to use O_WRONLY, then O_RDWR stateid. - */ - if (filp) - msg.rpc_cred = ((struct nfs4_state *)filp->private_data)->owner->so_cred; - else - msg.rpc_cred = NFS_I(inode)->mm_cred; - fattr->valid = 0; status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply commit: %d\n", status); @@ -1467,8 +1433,10 @@ static int nfs4_proc_file_open(struct inode *inode, struct file *filp) { struct dentry *dentry = filp->f_dentry; - struct nfs4_state *state; + struct nfs_open_context *ctx; + struct nfs4_state *state = NULL; struct rpc_cred *cred; + int status = -ENOMEM; dprintk("nfs4_proc_file_open: starting on (%.*s/%.*s)\n", (int)dentry->d_parent->d_name.len, @@ -1478,21 +1446,31 @@ nfs4_proc_file_open(struct inode *inode, /* Find our open stateid */ cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); + if (unlikely(cred == NULL)) + goto no_cred; + ctx = alloc_nfs_open_context(inode, cred); + if (unlikely(ctx == NULL)) + goto no_context; + status = -EIO; /* ERACE actually */ state = nfs4_find_state(inode, cred, filp->f_mode); - put_rpccred(cred); - if (state == NULL) { - printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__); - return -EIO; /* ERACE actually */ - } - nfs4_close_state(state, filp->f_mode); + if (unlikely(state == NULL)) + goto no_state; + ctx->state = state; if (filp->f_mode & FMODE_WRITE) { lock_kernel(); - nfs_set_mmcred(inode, state->owner->so_cred); - nfs_begin_data_update(inode); + nfs_set_mmcontext(inode, ctx); unlock_kernel(); + nfs_begin_data_update(inode); } - filp->private_data = state; + filp->private_data = ctx; return 0; +no_state: + printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__); + put_nfs_open_context(ctx); +no_context: + put_rpccred(cred); +no_cred: + return status; } /* @@ -1501,37 +1479,18 @@ nfs4_proc_file_open(struct inode *inode, static int nfs4_proc_file_release(struct inode *inode, struct file *filp) { - struct nfs4_state *state = (struct nfs4_state *)filp->private_data; + struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data; - if (state) - nfs4_close_state(state, filp->f_mode); - if (filp->f_mode & FMODE_WRITE) { - lock_kernel(); + if (filp->f_mode & FMODE_WRITE) nfs_end_data_update(inode); - unlock_kernel(); + if (ctx != NULL) { + if (ctx->state != NULL) + nfs4_close_state(ctx->state, filp->f_mode); + put_nfs_open_context(ctx); } return 0; } -/* - * Set up the nfspage struct with the right state info and credentials - */ -static void -nfs4_request_init(struct nfs_page *req, struct file *filp) -{ - struct nfs4_state *state; - - if (!filp) { - req->wb_cred = get_rpccred(NFS_I(req->wb_inode)->mm_cred); - req->wb_state = NULL; - return; - } - state = (struct nfs4_state *)filp->private_data; - req->wb_state = state; - req->wb_cred = get_rpccred(state->owner->so_cred); - req->wb_lockowner = current->files; -} - static int nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) { @@ -1639,35 +1598,15 @@ nfs4_handle_error(struct nfs_server *ser return nfs4_map_errors(ret); } - -static int -nfs4_request_compatible(struct nfs_page *req, struct file *filp, struct page *page) +int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port) { - struct nfs4_state *state = NULL; - struct rpc_cred *cred = NULL; - - if (req->wb_file != filp) - return 0; - if (req->wb_page != page) - return 0; - state = (struct nfs4_state *)filp->private_data; - if (req->wb_state != state) - return 0; - if (req->wb_lockowner != current->files) - return 0; - cred = state->owner->so_cred; - if (req->wb_cred != cred) - return 0; - return 1; -} - -int -nfs4_proc_setclientid(struct nfs4_client *clp, - u32 program, unsigned short port) -{ - u32 *p; - struct nfs4_setclientid setclientid; - struct timespec tv; + static nfs4_verifier sc_verifier; + static int initialized; + + struct nfs4_setclientid setclientid = { + .sc_verifier = &sc_verifier, + .sc_prog = program, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], .rpc_argp = &setclientid, @@ -1675,15 +1614,24 @@ nfs4_proc_setclientid(struct nfs4_client .rpc_cred = clp->cl_cred, }; - tv = CURRENT_TIME; - p = (u32*)setclientid.sc_verifier.data; - *p++ = (u32)tv.tv_sec; - *p = (u32)tv.tv_nsec; - setclientid.sc_name = clp->cl_ipaddr; - sprintf(setclientid.sc_netid, "tcp"); - sprintf(setclientid.sc_uaddr, "%s.%d.%d", clp->cl_ipaddr, port >> 8, port & 255); - setclientid.sc_prog = htonl(program); - setclientid.sc_cb_ident = 0; + if (!initialized) { + struct timespec boot_time; + u32 *p; + + initialized = 1; + boot_time = CURRENT_TIME; + p = (u32*)sc_verifier.data; + *p++ = htonl((u32)boot_time.tv_sec); + *p = htonl((u32)boot_time.tv_nsec); + } + setclientid.sc_name_len = scnprintf(setclientid.sc_name, + sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u", + clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr)); + setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, + sizeof(setclientid.sc_netid), "tcp"); + setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, + sizeof(setclientid.sc_uaddr), "%s.%d.%d", + clp->cl_ipaddr, port >> 8, port & 255); return rpc_call_sync(clp->cl_rpcclient, &msg, 0); } @@ -1938,13 +1886,14 @@ out: static int nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) { + struct nfs_open_context *ctx; struct nfs4_state *state; unsigned long timeout = NFS4_LOCK_MINTIMEOUT; int status; /* verify open state */ - state = (struct nfs4_state *)filp->private_data; - BUG_ON(!state); + ctx = (struct nfs_open_context *)filp->private_data; + state = ctx->state; if (request->fl_start < 0 || request->fl_end < 0) return -EINVAL; @@ -2004,8 +1953,6 @@ struct nfs_rpc_ops nfs_v4_clientops = { .commit_setup = nfs4_proc_commit_setup, .file_open = nfs4_proc_file_open, .file_release = nfs4_proc_file_release, - .request_init = nfs4_request_init, - .request_compatible = nfs4_request_compatible, .lock = nfs4_proc_lock, }; diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/nfs4state.c linux-2.6.6-18-file_ctx2/fs/nfs/nfs4state.c --- linux-2.6.6/fs/nfs/nfs4state.c 2004-05-09 22:31:58.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/nfs4state.c 2004-05-17 15:15:48.000000000 -0400 @@ -731,6 +731,8 @@ nfs4_reclaim_open_state(struct nfs4_stat int status = 0; list_for_each_entry(state, &sp->so_states, open_states) { + if (state->state == 0) + continue; status = nfs4_open_reclaim(sp, state); if (status >= 0) continue; diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/nfs4xdr.c linux-2.6.6-18-file_ctx2/fs/nfs/nfs4xdr.c --- linux-2.6.6/fs/nfs/nfs4xdr.c 2004-05-09 22:33:21.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/nfs4xdr.c 2004-05-17 15:17:25.000000000 -0400 @@ -388,6 +388,15 @@ struct compound_hdr { BUG_ON(!p); \ } while (0) +static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) +{ + uint32_t *p; + + p = xdr_reserve_space(xdr, 4 + len); + BUG_ON(p == NULL); + xdr_encode_opaque(p, str, len); +} + static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { uint32_t *p; @@ -887,15 +896,15 @@ static int encode_putrootfh(struct xdr_s return 0; } -static void encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner) +static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) { extern nfs4_stateid zero_stateid; nfs4_stateid stateid; uint32_t *p; RESERVE_SPACE(16); - if (state != NULL) { - nfs4_copy_stateid(&stateid, state, lockowner); + if (ctx->state != NULL) { + nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner); WRITEMEM(stateid.data, sizeof(stateid.data)); } else WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data)); @@ -908,7 +917,7 @@ static int encode_read(struct xdr_stream RESERVE_SPACE(4); WRITE32(OP_READ); - encode_stateid(xdr, args->state, args->lockowner); + encode_stateid(xdr, args->context); RESERVE_SPACE(12); WRITE64(args->offset); @@ -947,7 +956,8 @@ static int encode_readdir(struct xdr_str static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req) { struct rpc_auth *auth = req->rq_task->tk_auth; - int replen; + unsigned int count = readlink->count - 5; + unsigned int replen; uint32_t *p; RESERVE_SPACE(4); @@ -958,7 +968,7 @@ static int encode_readlink(struct xdr_st * + OP_READLINK + status = 7 */ replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; - xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, readlink->count); + xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, count); return 0; } @@ -1030,26 +1040,18 @@ static int encode_setattr(struct xdr_str static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid) { - uint32_t total_len; - uint32_t len1, len2, len3; uint32_t *p; - len1 = strlen(setclientid->sc_name); - len2 = strlen(setclientid->sc_netid); - len3 = strlen(setclientid->sc_uaddr); - total_len = XDR_QUADLEN(len1) + XDR_QUADLEN(len2) + XDR_QUADLEN(len3); - total_len = (total_len << 2) + 24 + sizeof(setclientid->sc_verifier.data); - - RESERVE_SPACE(total_len); + RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data)); WRITE32(OP_SETCLIENTID); - WRITEMEM(setclientid->sc_verifier.data, sizeof(setclientid->sc_verifier.data)); - WRITE32(len1); - WRITEMEM(setclientid->sc_name, len1); + WRITEMEM(setclientid->sc_verifier->data, sizeof(setclientid->sc_verifier->data)); + + encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); + RESERVE_SPACE(4); WRITE32(setclientid->sc_prog); - WRITE32(len2); - WRITEMEM(setclientid->sc_netid, len2); - WRITE32(len3); - WRITEMEM(setclientid->sc_uaddr, len3); + encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid); + encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); + RESERVE_SPACE(4); WRITE32(setclientid->sc_cb_ident); return 0; @@ -1074,7 +1076,7 @@ static int encode_write(struct xdr_strea RESERVE_SPACE(4); WRITE32(OP_WRITE); - encode_stateid(xdr, args->state, args->lockowner); + encode_stateid(xdr, args->context); RESERVE_SPACE(16); WRITE64(args->offset); @@ -2921,10 +2923,10 @@ static int decode_readlink(struct xdr_st */ strlen = (uint32_t *) kmap_atomic(rcvbuf->pages[0], KM_USER0); len = ntohl(*strlen); - if (len > PAGE_CACHE_SIZE - 5) { - printk(KERN_WARNING "nfs: server returned giant symlink!\n"); + if (len > rcvbuf->page_len) { + dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); kunmap_atomic(strlen, KM_USER0); - return -EIO; + return -ENAMETOOLONG; } *strlen = len; diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/pagelist.c linux-2.6.6-18-file_ctx2/fs/nfs/pagelist.c --- linux-2.6.6/fs/nfs/pagelist.c 2004-05-09 22:33:19.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/pagelist.c 2004-05-17 15:17:17.000000000 -0400 @@ -36,7 +36,6 @@ nfs_page_alloc(void) if (p) { memset(p, 0, sizeof(*p)); INIT_LIST_HEAD(&p->wb_list); - init_waitqueue_head(&p->wb_wait); } return p; } @@ -62,7 +61,7 @@ nfs_page_free(struct nfs_page *p) * User should ensure it is safe to sleep in this function. */ struct nfs_page * -nfs_create_request(struct file *file, struct inode *inode, +nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, struct page *page, unsigned int offset, unsigned int count) { @@ -94,33 +93,38 @@ nfs_create_request(struct file *file, st req->wb_offset = offset; req->wb_pgbase = offset; req->wb_bytes = count; - req->wb_inode = inode; req->wb_count = 1; - server->rpc_ops->request_init(req, file); + req->wb_context = get_nfs_open_context(ctx); return req; } /** + * nfs_unlock_request - Unlock request and wake up sleepers. + * @req: + */ +void nfs_unlock_request(struct nfs_page *req) +{ + if (!NFS_WBACK_BUSY(req)) { + printk(KERN_ERR "NFS: Invalid unlock attempted\n"); + BUG(); + } + smp_mb__before_clear_bit(); + clear_bit(PG_BUSY, &req->wb_flags); + smp_mb__after_clear_bit(); + wake_up_all(&req->wb_context->waitq); + nfs_release_request(req); +} + +/** * nfs_clear_request - Free up all resources allocated to the request * @req: * - * Release all resources associated with a write request after it + * Release page resources associated with a write request after it * has completed. */ void nfs_clear_request(struct nfs_page *req) { - if (req->wb_state) - req->wb_state = NULL; - /* Release struct file or cached credential */ - if (req->wb_file) { - fput(req->wb_file); - req->wb_file = NULL; - } - if (req->wb_cred) { - put_rpccred(req->wb_cred); - req->wb_cred = NULL; - } if (req->wb_page) { page_cache_release(req->wb_page); req->wb_page = NULL; @@ -151,6 +155,7 @@ nfs_release_request(struct nfs_page *req /* Release struct file or cached credential */ nfs_clear_request(req); + put_nfs_open_context(req->wb_context); nfs_page_free(req); } @@ -194,12 +199,12 @@ nfs_list_add_request(struct nfs_page *re int nfs_wait_on_request(struct nfs_page *req) { - struct inode *inode = req->wb_inode; + struct inode *inode = req->wb_context->inode; struct rpc_clnt *clnt = NFS_CLIENT(inode); if (!NFS_WBACK_BUSY(req)) return 0; - return nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req)); + return nfs_wait_event(clnt, req->wb_context->waitq, !NFS_WBACK_BUSY(req)); } /** @@ -224,7 +229,11 @@ nfs_coalesce_requests(struct list_head * req = nfs_list_entry(head->next); if (prev) { - if (req->wb_cred != prev->wb_cred) + if (req->wb_context->cred != prev->wb_context->cred) + break; + if (req->wb_context->lockowner != prev->wb_context->lockowner) + break; + if (req->wb_context->state != prev->wb_context->state) break; if (req->wb_index != (prev->wb_index + 1)) break; diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/proc.c linux-2.6.6-18-file_ctx2/fs/nfs/proc.c --- linux-2.6.6/fs/nfs/proc.c 2004-05-09 22:33:20.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/proc.c 2004-05-17 15:17:17.000000000 -0400 @@ -49,18 +49,6 @@ extern struct rpc_procinfo nfs_procedures[]; -static struct rpc_cred * -nfs_cred(struct inode *inode, struct file *filp) -{ - struct rpc_cred *cred = NULL; - - if (filp) - cred = (struct rpc_cred *)filp->private_data; - if (!cred) - cred = NFS_I(inode)->mm_cred; - return cred; -} - /* * Bare-bones access to getattr: this is for nfs_read_super. */ @@ -167,8 +155,7 @@ nfs_proc_readlink(struct inode *inode, s return status; } -static int -nfs_proc_read(struct nfs_read_data *rdata, struct file *filp) +static int nfs_proc_read(struct nfs_read_data *rdata) { int flags = rdata->flags; struct inode * inode = rdata->inode; @@ -177,15 +164,14 @@ nfs_proc_read(struct nfs_read_data *rdat .rpc_proc = &nfs_procedures[NFSPROC_READ], .rpc_argp = &rdata->args, .rpc_resp = &rdata->res, + .rpc_resp = rdata->cred, }; int status; dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); fattr->valid = 0; - msg.rpc_cred = nfs_cred(inode, filp); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); - if (status >= 0) { nfs_refresh_inode(inode, fattr); /* Emulate the eof flag, which isn't normally needed in NFSv2 @@ -198,8 +184,7 @@ nfs_proc_read(struct nfs_read_data *rdat return status; } -static int -nfs_proc_write(struct nfs_write_data *wdata, struct file *filp) +static int nfs_proc_write(struct nfs_write_data *wdata) { int flags = wdata->flags; struct inode * inode = wdata->inode; @@ -208,13 +193,13 @@ nfs_proc_write(struct nfs_write_data *wd .rpc_proc = &nfs_procedures[NFSPROC_WRITE], .rpc_argp = &wdata->args, .rpc_resp = &wdata->res, + .rpc_resp = wdata->cred, }; int status; dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); fattr->valid = 0; - msg.rpc_cred = nfs_cred(inode, filp); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) { nfs_refresh_inode(inode, fattr); @@ -619,27 +604,6 @@ nfs_proc_commit_setup(struct nfs_write_d BUG(); } -/* - * Set up the nfspage struct with the right credentials - */ -static void -nfs_request_init(struct nfs_page *req, struct file *filp) -{ - req->wb_cred = get_rpccred(nfs_cred(req->wb_inode, filp)); -} - -static int -nfs_request_compatible(struct nfs_page *req, struct file *filp, struct page *page) -{ - if (req->wb_file != filp) - return 0; - if (req->wb_page != page) - return 0; - if (req->wb_cred != nfs_file_cred(filp)) - return 0; - return 1; -} - static int nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) { @@ -680,7 +644,5 @@ struct nfs_rpc_ops nfs_v2_clientops = { .commit_setup = nfs_proc_commit_setup, .file_open = nfs_open, .file_release = nfs_release, - .request_init = nfs_request_init, - .request_compatible = nfs_request_compatible, .lock = nfs_proc_lock, }; diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/read.c linux-2.6.6-18-file_ctx2/fs/nfs/read.c --- linux-2.6.6/fs/nfs/read.c 2004-05-09 22:31:55.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/read.c 2004-05-17 15:17:25.000000000 -0400 @@ -93,19 +93,19 @@ int nfs_return_empty_page(struct page *p /* * Read a page synchronously. */ -static int -nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page) +static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, + struct page *page) { unsigned int rsize = NFS_SERVER(inode)->rsize; unsigned int count = PAGE_CACHE_SIZE; int result; struct nfs_read_data rdata = { .flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0), - .cred = NULL, + .cred = ctx->cred, .inode = inode, .args = { .fh = NFS_FH(inode), - .lockowner = current->files, + .context = ctx, .pages = &page, .pgbase = 0UL, .count = rsize, @@ -135,7 +135,7 @@ nfs_readpage_sync(struct file *file, str rdata.args.count); lock_kernel(); - result = NFS_PROTO(inode)->read(&rdata, file); + result = NFS_PROTO(inode)->read(&rdata); unlock_kernel(); /* @@ -169,8 +169,8 @@ io_error: return result; } -static int -nfs_readpage_async(struct file *file, struct inode *inode, struct page *page) +static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, + struct page *page) { LIST_HEAD(one_request); struct nfs_page *new; @@ -179,7 +179,7 @@ nfs_readpage_async(struct file *file, st len = nfs_page_length(inode, page); if (len == 0) return nfs_return_empty_page(page); - new = nfs_create_request(file, inode, page, 0, len); + new = nfs_create_request(ctx, inode, page, 0, len); if (IS_ERR(new)) { unlock_page(page); return PTR_ERR(new); @@ -202,8 +202,8 @@ static void nfs_readpage_release(struct nfs_unlock_request(req); dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", - req->wb_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_inode), + req->wb_context->inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->inode), req->wb_bytes, (long long)req_offset(req)); } @@ -217,16 +217,15 @@ static void nfs_read_rpcsetup(struct nfs struct inode *inode; data->req = req; - data->inode = inode = req->wb_inode; - data->cred = req->wb_cred; + data->inode = inode = req->wb_context->inode; + data->cred = req->wb_context->cred; data->args.fh = NFS_FH(inode); data->args.offset = req_offset(req) + offset; data->args.pgbase = req->wb_pgbase + offset; data->args.pages = data->pagevec; data->args.count = count; - data->args.lockowner = req->wb_lockowner; - data->args.state = req->wb_state; + data->args.context = req->wb_context; data->res.fattr = &data->fattr; data->res.count = count; @@ -394,7 +393,7 @@ nfs_pagein_list(struct list_head *head, while (!list_empty(head)) { pages += nfs_coalesce_requests(head, &one_request, rpages); req = nfs_list_entry(one_request.next); - error = nfs_pagein_one(&one_request, req->wb_inode); + error = nfs_pagein_one(&one_request, req->wb_context->inode); if (error < 0) break; } @@ -498,9 +497,9 @@ void nfs_readpage_result(struct rpc_task * - The error flag is set for this page. This happens only when a * previous async read operation failed. */ -int -nfs_readpage(struct file *file, struct page *page) +int nfs_readpage(struct file *file, struct page *page) { + struct nfs_open_context *ctx; struct inode *inode = page->mapping->host; int error; @@ -517,25 +516,33 @@ nfs_readpage(struct file *file, struct p if (error) goto out_error; + lock_kernel(); + if (file != NULL) + ctx = (struct nfs_open_context *)file->private_data; + else + ctx = NFS_I(inode)->mm_context; + get_nfs_open_context(ctx); if (!IS_SYNC(inode)) { - error = nfs_readpage_async(file, inode, page); + error = nfs_readpage_async(ctx, inode, page); goto out; } - error = nfs_readpage_sync(file, inode, page); + error = nfs_readpage_sync(ctx, inode, page); if (error < 0 && IS_SWAPFILE(inode)) printk("Aiee.. nfs swap-in of page failed!\n"); out: + unlock_kernel(); + put_nfs_open_context(ctx); return error; out_error: unlock_page(page); - goto out; + return error; } struct nfs_readdesc { struct list_head *head; - struct file *filp; + struct nfs_open_context *ctx; }; static int @@ -550,7 +557,7 @@ readpage_async_filler(void *data, struct len = nfs_page_length(inode, page); if (len == 0) return nfs_return_empty_page(page); - new = nfs_create_request(desc->filp, inode, page, 0, len); + new = nfs_create_request(desc->ctx, inode, page, 0, len); if (IS_ERR(new)) { SetPageError(page); unlock_page(page); @@ -563,13 +570,11 @@ readpage_async_filler(void *data, struct return 0; } -int -nfs_readpages(struct file *filp, struct address_space *mapping, +int nfs_readpages(struct file *filp, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { LIST_HEAD(head); struct nfs_readdesc desc = { - .filp = filp, .head = &head, }; struct inode *inode = mapping->host; @@ -581,12 +586,20 @@ nfs_readpages(struct file *filp, struct (long long)NFS_FILEID(inode), nr_pages); + lock_kernel(); + if (filp != NULL) + desc.ctx = (struct nfs_open_context *)filp->private_data; + else + desc.ctx = NFS_I(inode)->mm_context; + get_nfs_open_context(desc.ctx); ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); if (!list_empty(&head)) { int err = nfs_pagein_list(&head, server->rpages); if (!ret) ret = err; } + put_nfs_open_context(desc.ctx); + unlock_kernel(); return ret; } diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/unlink.c linux-2.6.6-18-file_ctx2/fs/nfs/unlink.c --- linux-2.6.6/fs/nfs/unlink.c 2004-05-09 22:33:20.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/unlink.c 2004-05-17 15:17:02.000000000 -0400 @@ -211,7 +211,6 @@ nfs_complete_unlink(struct dentry *dentr data->count++; nfs_copy_dname(dentry, data); dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; - if (data->task.tk_rpcwait == &nfs_delete_queue) - rpc_wake_up_task(&data->task); + rpc_wake_up_task(&data->task); nfs_put_unlinkdata(data); } diff -u --recursive --new-file --show-c-function linux-2.6.6/fs/nfs/write.c linux-2.6.6-18-file_ctx2/fs/nfs/write.c --- linux-2.6.6/fs/nfs/write.c 2004-05-09 22:32:54.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/fs/nfs/write.c 2004-05-17 15:17:25.000000000 -0400 @@ -71,7 +71,8 @@ /* * Local function declarations */ -static struct nfs_page * nfs_update_request(struct file*, struct inode *, +static struct nfs_page * nfs_update_request(struct nfs_open_context*, + struct inode *, struct page *, unsigned int, unsigned int); static void nfs_writeback_done_partial(struct nfs_write_data *, int); @@ -173,7 +174,7 @@ static void nfs_mark_uptodate(struct pag * Write a page synchronously. * Offset is the data offset within the page. */ -static int nfs_writepage_sync(struct file *file, struct inode *inode, +static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, struct page *page, unsigned int offset, unsigned int count, int how) { @@ -181,11 +182,11 @@ static int nfs_writepage_sync(struct fil int result, written = 0; struct nfs_write_data wdata = { .flags = how, - .cred = NULL, + .cred = ctx->cred, .inode = inode, .args = { .fh = NFS_FH(inode), - .lockowner = current->files, + .context = ctx, .pages = &page, .stable = NFS_FILE_SYNC, .pgbase = offset, @@ -208,7 +209,7 @@ static int nfs_writepage_sync(struct fil wdata.args.count = count; wdata.args.offset = page_offset(page) + wdata.args.pgbase; - result = NFS_PROTO(inode)->write(&wdata, file); + result = NFS_PROTO(inode)->write(&wdata); if (result < 0) { /* Must mark the page invalid after I/O error */ @@ -240,13 +241,14 @@ io_error: return written ? written : result; } -static int nfs_writepage_async(struct file *file, struct inode *inode, - struct page *page, unsigned int offset, unsigned int count) +static int nfs_writepage_async(struct nfs_open_context *ctx, + struct inode *inode, struct page *page, + unsigned int offset, unsigned int count) { struct nfs_page *req; int status; - req = nfs_update_request(file, inode, page, offset, count); + req = nfs_update_request(ctx, inode, page, offset, count); status = (IS_ERR(req)) ? PTR_ERR(req) : 0; if (status < 0) goto out; @@ -273,6 +275,7 @@ static int wb_priority(struct writeback_ */ int nfs_writepage(struct page *page, struct writeback_control *wbc) { + struct nfs_open_context *ctx; struct inode *inode = page->mapping->host; unsigned long end_index; unsigned offset = PAGE_CACHE_SIZE; @@ -308,22 +311,23 @@ int nfs_writepage(struct page *page, str goto out; do_it: lock_kernel(); + ctx = get_nfs_open_context(NFS_I(inode)->mm_context); if (!IS_SYNC(inode) && inode_referenced) { - err = nfs_writepage_async(NULL, inode, page, 0, offset); + err = nfs_writepage_async(ctx, inode, page, 0, offset); if (err >= 0) { err = 0; if (wbc->for_reclaim) err = WRITEPAGE_ACTIVATE; } } else { - err = nfs_writepage_sync(NULL, inode, page, 0, - offset, priority); + err = nfs_writepage_sync(ctx, inode, page, 0, offset, priority); if (err >= 0) { if (err != offset) redirty_page_for_writepage(wbc, page); err = 0; } } + put_nfs_open_context(ctx); unlock_kernel(); out: if (err != WRITEPAGE_ACTIVATE) @@ -404,7 +408,7 @@ nfs_inode_remove_request(struct nfs_page BUG_ON (!NFS_WBACK_BUSY(req)); spin_lock(&nfs_wreq_lock); - inode = req->wb_inode; + inode = req->wb_context->inode; nfsi = NFS_I(inode); radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); nfsi->npages--; @@ -450,7 +454,7 @@ nfs_find_request(struct inode *inode, un static void nfs_mark_request_dirty(struct nfs_page *req) { - struct inode *inode = req->wb_inode; + struct inode *inode = req->wb_context->inode; struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&nfs_wreq_lock); @@ -467,7 +471,7 @@ nfs_mark_request_dirty(struct nfs_page * static inline int nfs_dirty_request(struct nfs_page *req) { - struct nfs_inode *nfsi = NFS_I(req->wb_inode); + struct nfs_inode *nfsi = NFS_I(req->wb_context->inode); return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty; } @@ -478,7 +482,7 @@ nfs_dirty_request(struct nfs_page *req) static void nfs_mark_request_commit(struct nfs_page *req) { - struct inode *inode = req->wb_inode; + struct inode *inode = req->wb_context->inode; struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&nfs_wreq_lock); @@ -619,9 +623,9 @@ static int nfs_wait_on_write_congestion( * * Note: Should always be called with the Page Lock held! */ -static struct nfs_page * -nfs_update_request(struct file* file, struct inode *inode, struct page *page, - unsigned int offset, unsigned int bytes) +static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, + struct inode *inode, struct page *page, + unsigned int offset, unsigned int bytes) { struct nfs_server *server = NFS_SERVER(inode); struct nfs_page *req, *new = NULL; @@ -668,13 +672,9 @@ nfs_update_request(struct file* file, st } spin_unlock(&nfs_wreq_lock); - new = nfs_create_request(file, inode, page, offset, bytes); + new = nfs_create_request(ctx, inode, page, offset, bytes); if (IS_ERR(new)) return new; - if (file) { - new->wb_file = file; - get_file(file); - } } /* We have a request for our page. @@ -684,7 +684,7 @@ nfs_update_request(struct file* file, st * request. */ rqend = req->wb_offset + req->wb_bytes; - if (req->wb_file != file + if (req->wb_context != ctx || req->wb_page != page || !nfs_dirty_request(req) || offset > rqend || end < req->wb_offset) { @@ -705,9 +705,9 @@ nfs_update_request(struct file* file, st return req; } -int -nfs_flush_incompatible(struct file *file, struct page *page) +int nfs_flush_incompatible(struct file *file, struct page *page) { + struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; struct inode *inode = page->mapping->host; struct nfs_page *req; int status = 0; @@ -721,7 +721,7 @@ nfs_flush_incompatible(struct file *file */ req = nfs_find_request(inode, page->index); if (req) { - if (!NFS_PROTO(inode)->request_compatible(req, file, page)) + if (req->wb_page != page || ctx != req->wb_context) status = nfs_wb_page(inode, page); nfs_release_request(req); } @@ -737,6 +737,7 @@ nfs_flush_incompatible(struct file *file int nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count) { + struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; struct dentry *dentry = file->f_dentry; struct inode *inode = page->mapping->host; struct nfs_page *req; @@ -747,7 +748,7 @@ int nfs_updatepage(struct file *file, st count, (long long)(page_offset(page) +offset)); if (IS_SYNC(inode)) { - status = nfs_writepage_sync(file, inode, page, offset, count, 0); + status = nfs_writepage_sync(ctx, inode, page, offset, count, 0); if (status > 0) { if (offset == 0 && status == PAGE_CACHE_SIZE) SetPageUptodate(page); @@ -784,7 +785,7 @@ int nfs_updatepage(struct file *file, st * it out now. */ do { - req = nfs_update_request(file, inode, page, offset, count); + req = nfs_update_request(ctx, inode, page, offset, count); status = (IS_ERR(req)) ? PTR_ERR(req) : 0; if (status != -EBUSY) break; @@ -860,16 +861,15 @@ static void nfs_write_rpcsetup(struct nf * NB: take care not to mess about with data->commit et al. */ data->req = req; - data->inode = inode = req->wb_inode; - data->cred = req->wb_cred; + data->inode = inode = req->wb_context->inode; + data->cred = req->wb_context->cred; data->args.fh = NFS_FH(inode); data->args.offset = req_offset(req) + offset; data->args.pgbase = req->wb_pgbase + offset; data->args.pages = data->pagevec; data->args.count = count; - data->args.lockowner = req->wb_lockowner; - data->args.state = req->wb_state; + data->args.context = req->wb_context; data->res.fattr = &data->fattr; data->res.count = count; @@ -1029,7 +1029,7 @@ nfs_flush_list(struct list_head *head, i while (!list_empty(head)) { pages += nfs_coalesce_requests(head, &one_request, wpages); req = nfs_list_entry(one_request.next); - error = nfs_flush_one(&one_request, req->wb_inode, how); + error = nfs_flush_one(&one_request, req->wb_context->inode, how); if (error < 0) break; } @@ -1054,16 +1054,15 @@ static void nfs_writeback_done_partial(s struct page *page = req->wb_page; dprintk("NFS: write (%s/%Ld %d@%Ld)", - req->wb_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_inode), + req->wb_context->inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->inode), req->wb_bytes, (long long)req_offset(req)); if (status < 0) { ClearPageUptodate(page); SetPageError(page); - if (req->wb_file) - req->wb_file->f_error = status; + req->wb_context->error = status; dprintk(", error = %d\n", status); } else { #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) @@ -1104,16 +1103,15 @@ static void nfs_writeback_done_full(stru page = req->wb_page; dprintk("NFS: write (%s/%Ld %d@%Ld)", - req->wb_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_inode), + req->wb_context->inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->inode), req->wb_bytes, (long long)req_offset(req)); if (status < 0) { ClearPageUptodate(page); SetPageError(page); - if (req->wb_file) - req->wb_file->f_error = status; + req->wb_context->error = status; end_page_writeback(page); nfs_inode_remove_request(req); dprintk(", error = %d\n", status); @@ -1232,7 +1230,7 @@ static void nfs_commit_rpcsetup(struct l list_splice_init(head, &data->pages); first = nfs_list_entry(data->pages.next); last = nfs_list_entry(data->pages.prev); - inode = first->wb_inode; + inode = first->wb_context->inode; /* * Determine the offset range of requests in the COMMIT call. @@ -1246,7 +1244,7 @@ static void nfs_commit_rpcsetup(struct l len = 0; data->inode = inode; - data->cred = first->wb_cred; + data->cred = first->wb_context->cred; data->args.fh = NFS_FH(data->inode); data->args.offset = start; @@ -1313,13 +1311,12 @@ nfs_commit_done(struct rpc_task *task) nfs_list_remove_request(req); dprintk("NFS: commit (%s/%Ld %d@%Ld)", - req->wb_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_inode), + req->wb_context->inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->inode), req->wb_bytes, (long long)req_offset(req)); if (task->tk_status < 0) { - if (req->wb_file) - req->wb_file->f_error = task->tk_status; + req->wb_context->error = task->tk_status; nfs_inode_remove_request(req); dprintk(", error = %d\n", task->tk_status); goto next; diff -u --recursive --new-file --show-c-function linux-2.6.6/include/linux/nfs_fs.h linux-2.6.6-18-file_ctx2/include/linux/nfs_fs.h --- linux-2.6.6/include/linux/nfs_fs.h 2004-05-09 22:32:28.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/include/linux/nfs_fs.h 2004-05-17 15:17:17.000000000 -0400 @@ -84,6 +84,17 @@ struct nfs_access_cache { int err; }; +struct nfs_open_context { + atomic_t count; + struct inode * inode; + struct rpc_cred *cred; + struct nfs4_state *state; + fl_owner_t lockowner; + int error; + + wait_queue_head_t waitq; +}; + /* * nfs fs inode data in memory */ @@ -156,8 +167,8 @@ struct nfs_inode { ncommit, npages; - /* Credentials for shared mmap */ - struct rpc_cred *mm_cred; + /* Open context for shared mmap */ + struct nfs_open_context *mm_context; wait_queue_head_t nfs_i_wait; @@ -268,7 +279,7 @@ extern struct inode *nfs_fhget(struct su extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int nfs_permission(struct inode *, int, struct nameidata *); -extern void nfs_set_mmcred(struct inode *, struct rpc_cred *); +extern void nfs_set_mmcontext(struct inode *inode, struct nfs_open_context *ctx); extern int nfs_open(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *); extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); @@ -278,6 +289,9 @@ extern void nfs_end_attr_update(struct i extern void nfs_begin_data_update(struct inode *); extern void nfs_end_data_update(struct inode *); extern void nfs_end_data_update_defer(struct inode *); +extern struct nfs_open_context *alloc_nfs_open_context(struct inode *inode, struct rpc_cred *cred); +extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); +extern void put_nfs_open_context(struct nfs_open_context *ctx); /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ extern u32 root_nfs_parse_addr(char *name); /*__init*/ @@ -289,16 +303,15 @@ extern struct inode_operations nfs_file_ extern struct file_operations nfs_file_operations; extern struct address_space_operations nfs_file_aops; -static __inline__ struct rpc_cred * -nfs_file_cred(struct file *file) +static inline struct rpc_cred *nfs_file_cred(struct file *file) { - struct rpc_cred *cred = NULL; - if (file) - cred = (struct rpc_cred *)file->private_data; -#ifdef RPC_DEBUG - BUG_ON(cred && cred->cr_magic != RPCAUTH_CRED_MAGIC); -#endif - return cred; + if (file != NULL) { + struct nfs_open_context *ctx; + + ctx = (struct nfs_open_context*)file->private_data; + return ctx->cred; + } + return NULL; } /* @@ -306,6 +319,10 @@ nfs_file_cred(struct file *file) */ extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t, unsigned long); +extern ssize_t nfs_file_direct_read(struct kiocb *iocb, char *buf, + size_t count, loff_t pos); +extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char *buf, + size_t count, loff_t pos); /* * linux/fs/nfs/dir.c diff -u --recursive --new-file --show-c-function linux-2.6.6/include/linux/nfs_page.h linux-2.6.6-18-file_ctx2/include/linux/nfs_page.h --- linux-2.6.6/include/linux/nfs_page.h 2004-05-09 22:32:00.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/include/linux/nfs_page.h 2004-05-17 15:17:17.000000000 -0400 @@ -29,14 +29,9 @@ struct nfs_page { struct list_head wb_list, /* Defines state of page: */ *wb_list_head; /* read/write/commit */ - struct file *wb_file; - fl_owner_t wb_lockowner; - struct inode *wb_inode; - struct rpc_cred *wb_cred; - struct nfs4_state *wb_state; struct page *wb_page; /* page to read in/write out */ + struct nfs_open_context *wb_context; /* File state context info */ atomic_t wb_complete; /* i/os we're waiting for */ - wait_queue_head_t wb_wait; /* wait queue */ unsigned long wb_index; /* Offset >> PAGE_CACHE_SHIFT */ unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */ wb_pgbase, /* Start of page data */ @@ -50,9 +45,11 @@ struct nfs_page { #define NFS_NEED_COMMIT(req) (test_bit(PG_NEED_COMMIT,&(req)->wb_flags)) #define NFS_NEED_RESCHED(req) (test_bit(PG_NEED_RESCHED,&(req)->wb_flags)) -extern struct nfs_page *nfs_create_request(struct file *, struct inode *, - struct page *, - unsigned int, unsigned int); +extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx, + struct inode *inode, + struct page *page, + unsigned int offset, + unsigned int count); extern void nfs_clear_request(struct nfs_page *req); extern void nfs_release_request(struct nfs_page *req); @@ -64,6 +61,7 @@ extern int nfs_scan_list(struct list_hea extern int nfs_coalesce_requests(struct list_head *, struct list_head *, unsigned int); extern int nfs_wait_on_request(struct nfs_page *); +extern void nfs_unlock_request(struct nfs_page *req); extern spinlock_t nfs_wreq_lock; @@ -90,19 +88,6 @@ nfs_lock_request(struct nfs_page *req) return 1; } -static inline void -nfs_unlock_request(struct nfs_page *req) -{ - if (!NFS_WBACK_BUSY(req)) { - printk(KERN_ERR "NFS: Invalid unlock attempted\n"); - BUG(); - } - smp_mb__before_clear_bit(); - clear_bit(PG_BUSY, &req->wb_flags); - smp_mb__after_clear_bit(); - wake_up_all(&req->wb_wait); - nfs_release_request(req); -} /** * nfs_list_remove_request - Remove a request from its wb_list diff -u --recursive --new-file --show-c-function linux-2.6.6/include/linux/nfs_xdr.h linux-2.6.6-18-file_ctx2/include/linux/nfs_xdr.h --- linux-2.6.6/include/linux/nfs_xdr.h 2004-05-09 22:33:13.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/include/linux/nfs_xdr.h 2004-05-17 15:17:25.000000000 -0400 @@ -235,8 +235,7 @@ struct nfs_lockres { struct nfs_readargs { struct nfs_fh * fh; - fl_owner_t lockowner; - struct nfs4_state * state; + struct nfs_open_context *context; __u64 offset; __u32 count; unsigned int pgbase; @@ -259,8 +258,7 @@ struct nfs_readres { struct nfs_writeargs { struct nfs_fh * fh; - fl_owner_t lockowner; - struct nfs4_state * state; + struct nfs_open_context *context; __u64 offset; __u32 count; enum nfs3_stable_how stable; @@ -597,13 +595,15 @@ struct nfs4_rename_res { }; struct nfs4_setclientid { - nfs4_verifier sc_verifier; /* request */ - char * sc_name; /* request */ + const nfs4_verifier * sc_verifier; /* request */ + unsigned int sc_name_len; + char sc_name[32]; /* request */ u32 sc_prog; /* request */ + unsigned int sc_netid_len; char sc_netid[4]; /* request */ + unsigned int sc_uaddr_len; char sc_uaddr[24]; /* request */ u32 sc_cb_ident; /* request */ - struct nfs4_client * sc_state; /* response */ }; struct nfs4_statfs_arg { @@ -674,9 +674,9 @@ struct nfs_rpc_ops { struct nfs_fh *, struct nfs_fattr *); int (*access) (struct inode *, struct rpc_cred *, int); int (*readlink)(struct inode *, struct page *); - int (*read) (struct nfs_read_data *, struct file *); - int (*write) (struct nfs_write_data *, struct file *); - int (*commit) (struct nfs_write_data *, struct file *); + int (*read) (struct nfs_read_data *); + int (*write) (struct nfs_write_data *); + int (*commit) (struct nfs_write_data *); struct inode * (*create) (struct inode *, struct qstr *, struct iattr *, int); int (*remove) (struct inode *, struct qstr *); @@ -708,8 +708,6 @@ struct nfs_rpc_ops { void (*commit_setup) (struct nfs_write_data *, int how); int (*file_open) (struct inode *, struct file *); int (*file_release) (struct inode *, struct file *); - void (*request_init)(struct nfs_page *, struct file *); - int (*request_compatible)(struct nfs_page *, struct file *, struct page *); int (*lock)(struct file *, int, struct file_lock *); }; diff -u --recursive --new-file --show-c-function linux-2.6.6/include/linux/sunrpc/gss_api.h linux-2.6.6-18-file_ctx2/include/linux/sunrpc/gss_api.h --- linux-2.6.6/include/linux/sunrpc/gss_api.h 2004-05-09 22:33:20.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/include/linux/sunrpc/gss_api.h 2004-05-17 15:16:19.000000000 -0400 @@ -50,46 +50,36 @@ u32 gss_verify_mic( u32 gss_delete_sec_context( struct gss_ctx **ctx_id); -/* We maintain a list of the pseudoflavors (equivalently, mechanism-qop-service - * triples) that we currently support: */ - -struct sup_sec_triple { - struct list_head triples; - u32 pseudoflavor; - struct gss_api_mech *mech; - u32 qop; - u32 service; +struct gss_api_mech * gss_mech_get_by_name(char *name); +struct gss_api_mech * gss_mech_get_by_pseudoflavor(u32 pseudoflavor); +u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); +char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); + +struct pf_desc { + u32 pseudoflavor; + u32 qop; + u32 service; + char *name; + char *auth_domain_name; }; -int gss_register_triple(u32 pseudoflavor, struct gss_api_mech *mech, u32 qop, - u32 service); -int gss_unregister_triple(u32 pseudoflavor); -int gss_pseudoflavor_supported(u32 pseudoflavor); -u32 gss_cmp_triples(u32 oid_len, char *oid_data, u32 qop, u32 service); -u32 gss_get_pseudoflavor(struct gss_ctx *ctx_id, u32 qop, u32 service); -u32 gss_pseudoflavor_to_service(u32 pseudoflavor); -/* Both return NULL on failure: */ -struct gss_api_mech * gss_pseudoflavor_to_mech(u32 pseudoflavor); -int gss_pseudoflavor_to_mechOID(u32 pseudoflavor, struct xdr_netobj *mech); - /* Different mechanisms (e.g., krb5 or spkm3) may implement gss-api, and - * mechanisms may be dynamically registered or unregistered by modules. - * Our only built-in mechanism is a trivial debugging mechanism that provides - * no actual security; the following function registers that mechanism: */ - -void gss_mech_register_debug(void); + * mechanisms may be dynamically registered or unregistered by modules. */ /* Each mechanism is described by the following struct: */ struct gss_api_mech { - struct xdr_netobj gm_oid; struct list_head gm_list; - atomic_t gm_count; + struct module *gm_owner; + struct xdr_netobj gm_oid; + char *gm_name; struct gss_api_ops *gm_ops; + /* pseudoflavors supported by this mechanism: */ + int gm_pf_num; + struct pf_desc gm_pfs[]; }; /* and must provide the following operations: */ struct gss_api_ops { - char *name; u32 (*gss_import_sec_context)( struct xdr_netobj *input_token, struct gss_ctx *ctx_id); @@ -107,29 +97,25 @@ struct gss_api_ops { void *internal_ctx_id); }; -/* Returns nonzero on failure. */ -int gss_mech_register(struct xdr_netobj *, struct gss_api_ops *); - -/* Returns nonzero iff someone still has a reference to this mech. */ -int gss_mech_unregister(struct gss_api_mech *); +int gss_mech_register(struct gss_api_mech *); +void gss_mech_unregister(struct gss_api_mech *); -/* Returns nonzer iff someone still has a reference to some mech. */ -int gss_mech_unregister_all(void); - -/* returns a mechanism descriptor given an OID, an increments the mechanism's +/* returns a mechanism descriptor given an OID, and increments the mechanism's * reference count. */ struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *); -/* Similar, but get by name like "krb5", "spkm", etc., instead of OID. */ +/* Returns a reference to a mechanism, given a name like "krb5" etc. */ struct gss_api_mech *gss_mech_get_by_name(char *); +/* Similar, but get by pseudoflavor. */ +struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); + /* Just increments the mechanism's reference count and returns its input: */ struct gss_api_mech * gss_mech_get(struct gss_api_mech *); -/* Returns nonzero iff you've released the last reference to this mech. - * Note that for every succesful gss_get_mech call there must be exactly - * one corresponding call to gss_mech_put.*/ -int gss_mech_put(struct gss_api_mech *); +/* For every succesful gss_mech_get or gss_mech_get_by_* call there must be a + * corresponding call to gss_mech_put. */ +void gss_mech_put(struct gss_api_mech *); #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_GSS_API_H */ diff -u --recursive --new-file --show-c-function linux-2.6.6/include/linux/sunrpc/gss_asn1.h linux-2.6.6-18-file_ctx2/include/linux/sunrpc/gss_asn1.h --- linux-2.6.6/include/linux/sunrpc/gss_asn1.h 2004-05-09 22:33:20.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/include/linux/sunrpc/gss_asn1.h 2004-05-17 15:16:13.000000000 -0400 @@ -81,5 +81,4 @@ int g_token_size( void g_make_token_header( struct xdr_netobj *mech, int body_size, - unsigned char **buf, - int tok_type); + unsigned char **buf); diff -u --recursive --new-file --show-c-function linux-2.6.6/include/linux/sunrpc/gss_krb5.h linux-2.6.6-18-file_ctx2/include/linux/sunrpc/gss_krb5.h --- linux-2.6.6/include/linux/sunrpc/gss_krb5.h 2004-05-09 22:32:37.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/include/linux/sunrpc/gss_krb5.h 2004-05-17 15:16:13.000000000 -0400 @@ -115,7 +115,7 @@ enum seal_alg { #define ENCTYPE_UNKNOWN 0x01ff s32 -krb5_make_checksum(s32 cksumtype, char *header, struct xdr_buf *body, +make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, struct xdr_netobj *cksum); u32 diff -u --recursive --new-file --show-c-function linux-2.6.6/include/linux/sunrpc/sched.h linux-2.6.6-18-file_ctx2/include/linux/sunrpc/sched.h --- linux-2.6.6/include/linux/sunrpc/sched.h 2004-05-09 22:32:53.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/include/linux/sunrpc/sched.h 2004-05-17 15:17:09.000000000 -0400 @@ -11,7 +11,9 @@ #include #include +#include #include +#include #include /* @@ -25,11 +27,18 @@ struct rpc_message { struct rpc_cred * rpc_cred; /* Credentials */ }; +struct rpc_wait_queue; +struct rpc_wait { + struct list_head list; /* wait queue links */ + struct list_head links; /* Links to related tasks */ + wait_queue_head_t waitq; /* sync: sleep on this q */ + struct rpc_wait_queue * rpc_waitq; /* RPC wait queue we're on */ +}; + /* * This is the RPC task struct */ struct rpc_task { - struct list_head tk_list; /* wait queue links */ #ifdef RPC_DEBUG unsigned long tk_magic; /* 0xf00baa */ #endif @@ -37,7 +46,6 @@ struct rpc_task { struct rpc_clnt * tk_client; /* RPC client */ struct rpc_rqst * tk_rqstp; /* RPC request */ int tk_status; /* result of last operation */ - struct rpc_wait_queue * tk_rpcwait; /* RPC wait queue we're on */ /* * RPC call state @@ -70,13 +78,18 @@ struct rpc_task { * you have a pathological interest in kernel oopses. */ struct timer_list tk_timer; /* kernel timer */ - wait_queue_head_t tk_wait; /* sync: sleep on this q */ unsigned long tk_timeout; /* timeout for rpc_sleep() */ unsigned short tk_flags; /* misc flags */ unsigned char tk_active : 1;/* Task has been activated */ unsigned char tk_priority : 2;/* Task priority */ unsigned long tk_runstate; /* Task run status */ - struct list_head tk_links; /* links to related tasks */ + struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could + * be any workqueue + */ + union { + struct work_struct tk_work; /* Async task work queue */ + struct rpc_wait tk_wait; /* RPC wait */ + } u; #ifdef RPC_DEBUG unsigned short tk_pid; /* debugging aid */ #endif @@ -87,11 +100,11 @@ struct rpc_task { /* 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) + if ((task=list_entry(pos, struct rpc_task, u.tk_wait.list)),1) #define task_for_first(task, head) \ if (!list_empty(head) && \ - ((task=list_entry((head)->next, struct rpc_task, tk_list)),1)) + ((task=list_entry((head)->next, struct rpc_task, u.tk_wait.list)),1)) /* .. and walking list of all tasks */ #define alltask_for_each(task, pos, head) \ @@ -124,22 +137,24 @@ typedef void (*rpc_action)(struct rpc_ #define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL) #define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT) -#define RPC_TASK_SLEEPING 0 -#define RPC_TASK_RUNNING 1 -#define RPC_IS_SLEEPING(t) (test_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate)) -#define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) +#define RPC_TASK_RUNNING 0 +#define RPC_TASK_QUEUED 1 +#define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) #define rpc_set_running(t) (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) -#define rpc_clear_running(t) (clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) - -#define rpc_set_sleeping(t) (set_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate)) - -#define rpc_clear_sleeping(t) \ +#define rpc_test_and_set_running(t) \ + (test_and_set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) +#define rpc_clear_running(t) \ do { \ smp_mb__before_clear_bit(); \ - clear_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate); \ + clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate); \ smp_mb__after_clear_bit(); \ - } while(0) + } while (0) + +#define RPC_IS_QUEUED(t) (test_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)) +#define rpc_set_queued(t) (set_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)) +#define rpc_test_and_clear_queued(t) \ + (test_and_clear_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)) /* * Task priorities. @@ -155,6 +170,7 @@ typedef void (*rpc_action)(struct rpc_ * RPC synchronization objects */ struct rpc_wait_queue { + spinlock_t lock; struct list_head tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */ unsigned long cookie; /* cookie of last task serviced */ unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */ @@ -175,6 +191,7 @@ struct rpc_wait_queue { #ifndef RPC_DEBUG # define RPC_WAITQ_INIT(var,qname) { \ + .lock = SPIN_LOCK_UNLOCKED, \ .tasks = { \ [0] = LIST_HEAD_INIT(var.tasks[0]), \ [1] = LIST_HEAD_INIT(var.tasks[1]), \ @@ -183,6 +200,7 @@ struct rpc_wait_queue { } #else # define RPC_WAITQ_INIT(var,qname) { \ + .lock = SPIN_LOCK_UNLOCKED, \ .tasks = { \ [0] = LIST_HEAD_INIT(var.tasks[0]), \ [1] = LIST_HEAD_INIT(var.tasks[1]), \ @@ -207,13 +225,10 @@ void rpc_killall_tasks(struct rpc_clnt int rpc_execute(struct rpc_task *); void rpc_run_child(struct rpc_task *parent, struct rpc_task *child, rpc_action action); -int rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *); -void rpc_remove_wait_queue(struct rpc_task *); void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, rpc_action action, rpc_action timer); -void rpc_add_timer(struct rpc_task *, rpc_action); void rpc_wake_up_task(struct rpc_task *); void rpc_wake_up(struct rpc_wait_queue *); struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); diff -u --recursive --new-file --show-c-function linux-2.6.6/include/linux/sunrpc/xprt.h linux-2.6.6-18-file_ctx2/include/linux/sunrpc/xprt.h --- linux-2.6.6/include/linux/sunrpc/xprt.h 2004-05-09 22:32:54.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/include/linux/sunrpc/xprt.h 2004-05-17 15:15:53.000000000 -0400 @@ -69,8 +69,7 @@ extern unsigned int xprt_tcp_slot_table_ * This describes a timeout strategy */ struct rpc_timeout { - unsigned long to_current, /* current timeout */ - to_initval, /* initial timeout */ + unsigned long to_initval, /* initial timeout */ to_maxval, /* max timeout */ to_increment; /* if !exponential */ unsigned int to_retries; /* max # of retries */ @@ -85,7 +84,6 @@ struct rpc_rqst { * This is the user-visible part */ struct rpc_xprt * rq_xprt; /* RPC client */ - struct rpc_timeout rq_timeout; /* timeout parms */ struct xdr_buf rq_snd_buf; /* send buffer */ struct xdr_buf rq_rcv_buf; /* recv buffer */ @@ -103,6 +101,9 @@ struct rpc_rqst { struct xdr_buf rq_private_buf; /* The receive buffer * used in the softirq. */ + unsigned long rq_majortimeo; /* major timeout alarm */ + unsigned long rq_timeout; /* Current timeout value */ + unsigned int rq_retries; /* # of retries */ /* * For authentication (e.g. auth_des) */ @@ -115,7 +116,6 @@ struct rpc_rqst { u32 rq_bytes_sent; /* Bytes we have sent */ unsigned long rq_xtime; /* when transmitted */ - int rq_ntimeo; int rq_ntrans; }; #define rq_svec rq_snd_buf.head @@ -210,7 +210,7 @@ void xprt_reserve(struct rpc_task *); int xprt_prepare_transmit(struct rpc_task *); void xprt_transmit(struct rpc_task *); void xprt_receive(struct rpc_task *); -int xprt_adjust_timeout(struct rpc_timeout *); +int xprt_adjust_timeout(struct rpc_rqst *req); void xprt_release(struct rpc_task *); void xprt_connect(struct rpc_task *); int xprt_clear_backlog(struct rpc_xprt *); diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/Makefile linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/Makefile --- linux-2.6.6/net/sunrpc/auth_gss/Makefile 2004-05-09 22:32:29.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/Makefile 2004-05-17 15:16:26.000000000 -0400 @@ -4,11 +4,11 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o -auth_rpcgss-objs := auth_gss.o gss_pseudoflavors.o gss_generic_token.o \ - sunrpcgss_syms.o gss_mech_switch.o svcauth_gss.o +auth_rpcgss-objs := auth_gss.o gss_generic_token.o \ + gss_mech_switch.o svcauth_gss.o gss_krb5_crypto.o obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \ - gss_krb5_crypto.o gss_krb5_seqnum.o + gss_krb5_seqnum.o diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/auth_gss.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/auth_gss.c --- linux-2.6.6/net/sunrpc/auth_gss/auth_gss.c 2004-05-09 22:32:29.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/auth_gss.c 2004-05-17 15:16:35.000000000 -0400 @@ -132,6 +132,8 @@ print_hexl(u32 *p, u_int length, u_int o } } +EXPORT_SYMBOL(print_hexl); + static inline struct gss_cl_ctx * gss_get_ctx(struct gss_cl_ctx *ctx) { @@ -280,7 +282,7 @@ err_free_ctx: kfree(ctx); err: *gc = NULL; - dprintk("RPC: gss_parse_init_downcall returning %d\n", err); + dprintk("RPC: gss_parse_init_downcall returning %d\n", err); return err; } @@ -311,8 +313,10 @@ __gss_find_upcall(struct gss_auth *gss_a if (pos->uid != uid) continue; atomic_inc(&pos->count); + dprintk("RPC: gss_find_upcall found msg %p\n", pos); return pos; } + dprintk("RPC: gss_find_upcall found nothing\n"); return NULL; } @@ -350,6 +354,8 @@ gss_upcall(struct rpc_clnt *clnt, struct uid_t uid = cred->cr_uid; int res = 0; + dprintk("RPC: %4u gss_upcall for uid %u\n", task->tk_pid, uid); + retry: spin_lock(&gss_auth->lock); gss_msg = __gss_find_upcall(gss_auth, uid); @@ -358,8 +364,10 @@ retry: if (gss_new == NULL) { spin_unlock(&gss_auth->lock); gss_new = kmalloc(sizeof(*gss_new), GFP_KERNEL); - if (!gss_new) + if (!gss_new) { + dprintk("RPC: %4u gss_upcall -ENOMEM\n", task->tk_pid); return -ENOMEM; + } goto retry; } gss_msg = gss_new; @@ -389,12 +397,14 @@ retry: spin_unlock(&gss_auth->lock); } gss_release_msg(gss_msg); + dprintk("RPC: %4u gss_upcall for uid %u result %d", task->tk_pid, + uid, res); return res; out_sleep: - /* Sleep forever */ task->tk_timeout = 0; rpc_sleep_on(&gss_msg->waitq, task, NULL, NULL); spin_unlock(&gss_auth->lock); + dprintk("RPC: %4u gss_upcall sleeping\n", task->tk_pid); if (gss_new) kfree(gss_new); /* Note: we drop the reference here: we are automatically removed @@ -477,12 +487,13 @@ gss_pipe_downcall(struct file *filp, con } else spin_unlock(&gss_auth->lock); rpc_release_client(clnt); + dprintk("RPC: gss_pipe_downcall returning length %u\n", mlen); return mlen; err: if (ctx) gss_destroy_ctx(ctx); rpc_release_client(clnt); - dprintk("RPC: gss_pipe_downcall returning %d\n", err); + dprintk("RPC: gss_pipe_downcall returning %d\n", err); return err; } @@ -520,6 +531,8 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg static unsigned long ratelimit; if (msg->errno < 0) { + dprintk("RPC: gss_pipe_destroy_msg releasing msg %p\n", + gss_msg); atomic_inc(&gss_msg->count); gss_unhash_msg(gss_msg); if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) { @@ -544,10 +557,11 @@ gss_create(struct rpc_clnt *clnt, rpc_au struct gss_auth *gss_auth; struct rpc_auth * auth; - dprintk("RPC: creating GSS authenticator for client %p\n",clnt); + dprintk("RPC: creating GSS authenticator for client %p\n",clnt); + if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) goto out_dec; - gss_auth->mech = gss_pseudoflavor_to_mech(flavor); + gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); if (!gss_auth->mech) { printk(KERN_WARNING "%s: Pseudoflavor %d not found!", __FUNCTION__, flavor); @@ -566,7 +580,7 @@ gss_create(struct rpc_clnt *clnt, rpc_au snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", clnt->cl_pathname, - gss_auth->mech->gm_ops->name); + gss_auth->mech->gm_name); gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); if (IS_ERR(gss_auth->dentry)) goto err_free; @@ -582,7 +596,8 @@ static void gss_destroy(struct rpc_auth *auth) { struct gss_auth *gss_auth; - dprintk("RPC: destroying GSS authenticator %p flavor %d\n", + + dprintk("RPC: destroying GSS authenticator %p flavor %d\n", auth, auth->au_flavor); gss_auth = container_of(auth, struct gss_auth, rpc_auth); @@ -597,8 +612,7 @@ gss_destroy(struct rpc_auth *auth) static void gss_destroy_ctx(struct gss_cl_ctx *ctx) { - - dprintk("RPC: gss_destroy_ctx\n"); + dprintk("RPC: gss_destroy_ctx\n"); if (ctx->gc_gss_ctx) gss_delete_sec_context(&ctx->gc_gss_ctx); @@ -617,7 +631,7 @@ gss_destroy_cred(struct rpc_cred *rc) { struct gss_cred *cred = (struct gss_cred *)rc; - dprintk("RPC: gss_destroy_cred \n"); + dprintk("RPC: gss_destroy_cred \n"); if (cred->gc_ctx) gss_put_ctx(cred->gc_ctx); @@ -629,7 +643,7 @@ gss_create_cred(struct rpc_auth *auth, s { struct gss_cred *cred = NULL; - dprintk("RPC: gss_create_cred for uid %d, flavor %d\n", + dprintk("RPC: gss_create_cred for uid %d, flavor %d\n", acred->uid, auth->au_flavor); if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL))) @@ -649,7 +663,7 @@ gss_create_cred(struct rpc_auth *auth, s return (struct rpc_cred *) cred; out_err: - dprintk("RPC: gss_create_cred failed\n"); + dprintk("RPC: gss_create_cred failed\n"); if (cred) gss_destroy_cred((struct rpc_cred *)cred); return NULL; } @@ -679,15 +693,16 @@ gss_marshal(struct rpc_task *task, u32 * struct xdr_buf verf_buf; u32 service; - dprintk("RPC: gss_marshal\n"); + dprintk("RPC: %4u gss_marshal\n", task->tk_pid); *p++ = htonl(RPC_AUTH_GSS); cred_len = p++; - service = gss_pseudoflavor_to_service(gss_cred->gc_flavor); + service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type, + gss_cred->gc_flavor); if (service == 0) { - dprintk("Bad pseudoflavor %d in gss_marshal\n", - gss_cred->gc_flavor); + dprintk("RPC: %4u Bad pseudoflavor %d in gss_marshal\n", + task->tk_pid, gss_cred->gc_flavor); goto out_put_ctx; } spin_lock(&ctx->gc_seq_lock); @@ -736,10 +751,8 @@ static int gss_refresh(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - struct rpc_xprt *xprt = task->tk_xprt; struct rpc_cred *cred = task->tk_msg.rpc_cred; - task->tk_timeout = xprt->timeout.to_current; if (!gss_cred_is_uptodate_ctx(cred)) return gss_upcall(clnt, task, cred); return 0; @@ -759,7 +772,7 @@ gss_validate(struct rpc_task *task, u32 u32 flav,len; u32 service; - dprintk("RPC: gss_validate\n"); + dprintk("RPC: %4u gss_validate\n", task->tk_pid); flav = ntohl(*p++); if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE) @@ -775,7 +788,8 @@ gss_validate(struct rpc_task *task, u32 if (gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic, &qop_state)) goto out_bad; - service = gss_pseudoflavor_to_service(gss_cred->gc_flavor); + service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type, + gss_cred->gc_flavor); switch (service) { case RPC_GSS_SVC_NONE: /* verifier data, flavor, length: */ @@ -789,33 +803,75 @@ gss_validate(struct rpc_task *task, u32 goto out_bad; } gss_put_ctx(ctx); + dprintk("RPC: %4u GSS gss_validate: gss_verify_mic succeeded.\n", + task->tk_pid); return p + XDR_QUADLEN(len); out_bad: gss_put_ctx(ctx); + dprintk("RPC: %4u gss_validate failed.\n", task->tk_pid); return NULL; } +static inline int +gss_wrap_req_integ(struct gss_cl_ctx *ctx, + kxdrproc_t encode, void *rqstp, u32 *p, void *obj) +{ + struct rpc_rqst *req = (struct rpc_rqst *)rqstp; + struct xdr_buf *snd_buf = &req->rq_snd_buf; + struct xdr_buf integ_buf; + u32 *integ_len = NULL; + struct xdr_netobj mic; + u32 offset, *q; + struct iovec *iov; + u32 maj_stat = 0; + int status = -EIO; + + integ_len = p++; + offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; + *p++ = htonl(req->rq_seqno); + + status = encode(rqstp, p, obj); + if (status) + return status; + + if (xdr_buf_subsegment(snd_buf, &integ_buf, + offset, snd_buf->len - offset)) + return status; + *integ_len = htonl(integ_buf.len); + + /* guess whether we're in the head or the tail: */ + if (snd_buf->page_len || snd_buf->tail[0].iov_len) + iov = snd_buf->tail; + else + iov = snd_buf->head; + p = iov->iov_base + iov->iov_len; + mic.data = (u8 *)(p + 1); + + maj_stat = gss_get_mic(ctx->gc_gss_ctx, + GSS_C_QOP_DEFAULT, &integ_buf, &mic); + status = -EIO; /* XXX? */ + if (maj_stat) + return status; + q = xdr_encode_opaque(p, NULL, mic.len); + + offset = (u8 *)q - (u8 *)p; + iov->iov_len += offset; + snd_buf->len += offset; + return 0; +} + static int gss_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *p, void *obj) { - struct rpc_rqst *req = (struct rpc_rqst *)rqstp; - struct xdr_buf *snd_buf = &req->rq_snd_buf; struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); - u32 *integ_len = NULL; int status = -EIO; - u32 maj_stat = 0; - struct xdr_buf integ_buf; - struct xdr_netobj mic; u32 service; - u32 offset, *q; - struct iovec *iov; - dprintk("RPC: gss_wrap_body\n"); - BUG_ON(!ctx); + dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid); if (ctx->gc_proc != RPC_GSS_PROC_DATA) { /* The spec seems a little ambiguous here, but I think that not * wrapping context destruction requests makes the most sense. @@ -823,103 +879,84 @@ gss_wrap_req(struct rpc_task *task, status = encode(rqstp, p, obj); goto out; } - service = gss_pseudoflavor_to_service(gss_cred->gc_flavor); + service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type, + gss_cred->gc_flavor); switch (service) { case RPC_GSS_SVC_NONE: status = encode(rqstp, p, obj); goto out; case RPC_GSS_SVC_INTEGRITY: - - integ_len = p++; - offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; - *p++ = htonl(req->rq_seqno); - - status = encode(rqstp, p, obj); - if (status) - goto out; - - if (xdr_buf_subsegment(snd_buf, &integ_buf, - offset, snd_buf->len - offset)) - goto out; - *integ_len = htonl(integ_buf.len); - - /* guess whether we're in the head or the tail: */ - if (snd_buf->page_len || snd_buf->tail[0].iov_len) - iov = snd_buf->tail; - else - iov = snd_buf->head; - p = iov->iov_base + iov->iov_len; - mic.data = (u8 *)(p + 1); - - maj_stat = gss_get_mic(ctx->gc_gss_ctx, - GSS_C_QOP_DEFAULT, &integ_buf, &mic); - status = -EIO; /* XXX? */ - if (maj_stat) - goto out; - q = xdr_encode_opaque(p, NULL, mic.len); - - offset = (u8 *)q - (u8 *)p; - iov->iov_len += offset; - snd_buf->len += offset; - break; + status = gss_wrap_req_integ(ctx, encode, rqstp, p, obj); + goto out; case RPC_GSS_SVC_PRIVACY: default: goto out; } - status = 0; out: gss_put_ctx(ctx); - dprintk("RPC: gss_wrap_req returning %d\n", status); + dprintk("RPC: %4u gss_wrap_req returning %d\n", task->tk_pid, status); return status; } +static inline int +gss_unwrap_resp_integ(struct gss_cl_ctx *ctx, + kxdrproc_t decode, void *rqstp, u32 **p, void *obj) +{ + struct rpc_rqst *req = (struct rpc_rqst *)rqstp; + struct xdr_buf *rcv_buf = &req->rq_rcv_buf; + struct xdr_buf integ_buf; + struct xdr_netobj mic; + u32 data_offset, mic_offset; + u32 integ_len; + u32 maj_stat; + int status = -EIO; + + integ_len = ntohl(*(*p)++); + if (integ_len & 3) + return status; + data_offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base; + mic_offset = integ_len + data_offset; + if (mic_offset > rcv_buf->len) + return status; + if (ntohl(*(*p)++) != req->rq_seqno) + return status; + + if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, + mic_offset - data_offset)) + return status; + + if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset)) + return status; + + maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, + &mic, NULL); + if (maj_stat != GSS_S_COMPLETE) + return status; + return 0; +} + static int gss_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, u32 *p, void *obj) { - struct rpc_rqst *req = (struct rpc_rqst *)rqstp; - struct xdr_buf *rcv_buf = &req->rq_rcv_buf; struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); - struct xdr_buf integ_buf; - struct xdr_netobj mic; int status = -EIO; - u32 maj_stat = 0; u32 service; - u32 data_offset, mic_offset; - u32 integ_len; - - BUG_ON(!ctx); if (ctx->gc_proc != RPC_GSS_PROC_DATA) goto out_decode; - service = gss_pseudoflavor_to_service(gss_cred->gc_flavor); + service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type, + gss_cred->gc_flavor); switch (service) { case RPC_GSS_SVC_NONE: goto out_decode; case RPC_GSS_SVC_INTEGRITY: - integ_len = ntohl(*p++); - if (integ_len & 3) - goto out; - data_offset = (u8 *)p - (u8 *)rcv_buf->head[0].iov_base; - mic_offset = integ_len + data_offset; - if (mic_offset > rcv_buf->len) - goto out; - if (ntohl(*p++) != req->rq_seqno) - goto out; - - if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, - mic_offset - data_offset)) - goto out; - - if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset)) - goto out; - - maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, - &mic, NULL); - if (maj_stat != GSS_S_COMPLETE) + status = gss_unwrap_resp_integ(ctx, decode, + rqstp, &p, obj); + if (status) goto out; break; case RPC_GSS_SVC_PRIVACY: @@ -930,7 +967,8 @@ out_decode: status = decode(rqstp, p, obj); out: gss_put_ctx(ctx); - dprintk("RPC: gss_unwrap_resp returning %d\n", status); + dprintk("RPC: %4u gss_unwrap_resp returning %d\n", task->tk_pid, + status); return status; } @@ -985,7 +1023,6 @@ out: static void __exit exit_rpcsec_gss(void) { gss_svc_shutdown(); - gss_mech_unregister_all(); rpcauth_unregister(&authgss_ops); } diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/gss_generic_token.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_generic_token.c --- linux-2.6.6/net/sunrpc/auth_gss/gss_generic_token.c 2004-05-09 22:32:27.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_generic_token.c 2004-05-17 15:16:26.000000000 -0400 @@ -32,6 +32,7 @@ */ #include +#include #include #include #include @@ -151,22 +152,23 @@ g_token_size(struct xdr_netobj *mech, un return(1 + der_length_size(body_size) + body_size); } +EXPORT_SYMBOL(g_token_size); + /* fills in a buffer with the token header. The buffer is assumed to be the right size. buf is advanced past the token header */ void -g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf, - int tok_type) +g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf) { *(*buf)++ = 0x60; der_write_length(buf, 4 + mech->len + body_size); *(*buf)++ = 0x06; *(*buf)++ = (unsigned char) mech->len; TWRITE_STR(*buf, mech->data, ((int) mech->len)); - *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff); - *(*buf)++ = (unsigned char) (tok_type&0xff); } +EXPORT_SYMBOL(g_make_token_header); + /* * Given a buffer containing a token, reads and verifies the token, * leaving buf advanced past the token header, and setting body_size @@ -221,9 +223,6 @@ g_verify_token_header(struct xdr_netobj if (ret) return(ret); - if ((*buf++ != ((tok_type>>8)&0xff)) || (*buf++ != (tok_type&0xff))) - return(G_WRONG_TOKID); - if (!ret) { *buf_in = buf; *body_size = toksize; @@ -232,6 +231,8 @@ g_verify_token_header(struct xdr_netobj return(ret); } +EXPORT_SYMBOL(g_verify_token_header); + /* Given a buffer containing a token, returns a copy of the mech oid in * the parameter mech. */ u32 diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_crypto.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_crypto.c --- linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_crypto.c 2004-05-09 22:31:59.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_crypto.c 2004-05-17 15:16:26.000000000 -0400 @@ -59,14 +59,14 @@ krb5_encrypt( struct scatterlist sg[1]; u8 local_iv[16] = {0}; - dprintk("RPC: krb5_encrypt: input data:\n"); + dprintk("RPC: krb5_encrypt: input data:\n"); print_hexl((u32 *)in, length, 0); if (length % crypto_tfm_alg_blocksize(tfm) != 0) goto out; if (crypto_tfm_alg_ivsize(tfm) > 16) { - dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n", + dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n", crypto_tfm_alg_ivsize(tfm)); goto out; } @@ -81,13 +81,15 @@ krb5_encrypt( ret = crypto_cipher_encrypt_iv(tfm, sg, sg, length, local_iv); - dprintk("RPC: krb5_encrypt: output data:\n"); + dprintk("RPC: krb5_encrypt: output data:\n"); print_hexl((u32 *)out, length, 0); out: - dprintk("krb5_encrypt returns %d\n",ret); + dprintk("RPC: krb5_encrypt returns %d\n",ret); return(ret); } +EXPORT_SYMBOL(krb5_encrypt); + u32 krb5_decrypt( struct crypto_tfm *tfm, @@ -100,14 +102,14 @@ krb5_decrypt( struct scatterlist sg[1]; u8 local_iv[16] = {0}; - dprintk("RPC: krb5_decrypt: input data:\n"); + dprintk("RPC: krb5_decrypt: input data:\n"); print_hexl((u32 *)in, length, 0); if (length % crypto_tfm_alg_blocksize(tfm) != 0) goto out; if (crypto_tfm_alg_ivsize(tfm) > 16) { - dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n", + dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n", crypto_tfm_alg_ivsize(tfm)); goto out; } @@ -121,13 +123,15 @@ krb5_decrypt( ret = crypto_cipher_decrypt_iv(tfm, sg, sg, length, local_iv); - dprintk("RPC: krb5_decrypt: output_data:\n"); + dprintk("RPC: krb5_decrypt: output_data:\n"); print_hexl((u32 *)out, length, 0); out: - dprintk("gss_k5decrypt returns %d\n",ret); + dprintk("RPC: gss_k5decrypt returns %d\n",ret); return(ret); } +EXPORT_SYMBOL(krb5_decrypt); + void buf_to_sg(struct scatterlist *sg, char *ptr, int len) { sg->page = virt_to_page(ptr); @@ -135,10 +139,9 @@ buf_to_sg(struct scatterlist *sg, char * sg->length = len; } -/* checksum the plaintext data and the first 8 bytes of the krb5 token header, - * as specified by the rfc: */ +/* checksum the plaintext data and hdrlen bytes of the token header */ s32 -krb5_make_checksum(s32 cksumtype, char *header, struct xdr_buf *body, +make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, struct xdr_netobj *cksum) { char *cksumname; @@ -153,7 +156,7 @@ krb5_make_checksum(s32 cksumtype, char * cksumname = "md5"; break; default: - dprintk("RPC: krb5_make_checksum:" + dprintk("RPC: krb5_make_checksum:" " unsupported checksum %d", cksumtype); goto out; } @@ -164,7 +167,7 @@ krb5_make_checksum(s32 cksumtype, char * goto out; crypto_digest_init(tfm); - buf_to_sg(sg, header, 8); + buf_to_sg(sg, header, hdrlen); crypto_digest_update(tfm, sg, 1); if (body->head[0].iov_len) { buf_to_sg(sg, body->head[0].iov_base, body->head[0].iov_len); @@ -202,3 +205,5 @@ out: crypto_free_tfm(tfm); return code; } + +EXPORT_SYMBOL(make_checksum); diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_mech.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_mech.c --- linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_mech.c 2004-05-09 22:32:54.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_mech.c 2004-05-17 15:16:19.000000000 -0400 @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -100,7 +99,7 @@ get_key(char **p, char *end, struct cryp alg_mode = CRYPTO_TFM_MODE_CBC; break; default: - dprintk("RPC: get_key: unsupported algorithm %d\n", alg); + dprintk("RPC: get_key: unsupported algorithm %d\n", alg); goto out_err_free_key; } if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) @@ -155,7 +154,7 @@ gss_import_sec_context_kerberos(struct x goto out_err_free_key2; ctx_id->internal_ctx_id = ctx; - dprintk("Succesfully imported new context.\n"); + dprintk("RPC: Succesfully imported new context.\n"); return 0; out_err_free_key2: @@ -197,7 +196,7 @@ gss_verify_mic_kerberos(struct gss_ctx if (!maj_stat && qop_state) *qstate = qop_state; - dprintk("RPC: gss_verify_mic_kerberos returning %d\n", maj_stat); + dprintk("RPC: gss_verify_mic_kerberos returning %d\n", maj_stat); return maj_stat; } @@ -211,41 +210,42 @@ gss_get_mic_kerberos(struct gss_ctx *ctx err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG); - dprintk("RPC: gss_get_mic_kerberos returning %d\n",err); + dprintk("RPC: gss_get_mic_kerberos returning %d\n",err); return err; } static struct gss_api_ops gss_kerberos_ops = { - .name = "krb5", .gss_import_sec_context = gss_import_sec_context_kerberos, .gss_get_mic = gss_get_mic_kerberos, .gss_verify_mic = gss_verify_mic_kerberos, .gss_delete_sec_context = gss_delete_sec_context_kerberos, }; -/* XXX error checking? reference counting? */ +static struct gss_api_mech gss_kerberos_mech = { + .gm_name = "krb5", + .gm_owner = THIS_MODULE, + .gm_ops = &gss_kerberos_ops, + .gm_pf_num = 2, + .gm_pfs = { + {RPC_AUTH_GSS_KRB5, 0, RPC_GSS_SVC_NONE, "krb5"}, + {RPC_AUTH_GSS_KRB5I, 0, RPC_GSS_SVC_INTEGRITY, "krb5i"}, + }, +}; + static int __init init_kerberos_module(void) { - struct gss_api_mech *gm; + int status; - if (gss_mech_register(&gss_mech_krb5_oid, &gss_kerberos_ops)) + status = gss_mech_register(&gss_kerberos_mech); + if (status) printk("Failed to register kerberos gss mechanism!\n"); - gm = gss_mech_get_by_OID(&gss_mech_krb5_oid); - gss_register_triple(RPC_AUTH_GSS_KRB5 , gm, 0, RPC_GSS_SVC_NONE); - gss_register_triple(RPC_AUTH_GSS_KRB5I, gm, 0, RPC_GSS_SVC_INTEGRITY); - if (svcauth_gss_register_pseudoflavor(RPC_AUTH_GSS_KRB5, "krb5")) - printk("Failed to register %s with server!\n", "krb5"); - if (svcauth_gss_register_pseudoflavor(RPC_AUTH_GSS_KRB5I, "krb5i")) - printk("Failed to register %s with server!\n", "krb5i"); - gss_mech_put(gm); - return 0; + return status; } static void __exit cleanup_kerberos_module(void) { - gss_unregister_triple(RPC_AUTH_GSS_KRB5I); - gss_unregister_triple(RPC_AUTH_GSS_KRB5); + gss_mech_unregister(&gss_kerberos_mech); } MODULE_LICENSE("GPL"); diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_seal.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_seal.c --- linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_seal.c 2004-05-09 22:31:55.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_seal.c 2004-05-17 15:16:41.000000000 -0400 @@ -91,7 +91,7 @@ krb5_make_token(struct krb5_ctx *ctx, in dprintk("RPC: gss_krb5_seal\n"); - now = jiffies; + now = get_seconds(); if (qop_req != 0) goto out_err; @@ -101,12 +101,12 @@ krb5_make_token(struct krb5_ctx *ctx, in checksum_type = CKSUMTYPE_RSA_MD5; break; default: - dprintk("RPC: gss_krb5_seal: ctx->signalg %d not" + dprintk("RPC: gss_krb5_seal: ctx->signalg %d not" " supported\n", ctx->signalg); goto out_err; } if (ctx->sealalg != SEAL_ALG_NONE && ctx->sealalg != SEAL_ALG_DES) { - dprintk("RPC: gss_krb5_seal: ctx->sealalg %d not supported\n", + dprintk("RPC: gss_krb5_seal: ctx->sealalg %d not supported\n", ctx->sealalg); goto out_err; } @@ -122,7 +122,10 @@ krb5_make_token(struct krb5_ctx *ctx, in token->len = g_token_size(&ctx->mech_used, 22 + tmsglen); ptr = token->data; - g_make_token_header(&ctx->mech_used, 22 + tmsglen, &ptr, toktype); + g_make_token_header(&ctx->mech_used, 22 + tmsglen, &ptr); + + *ptr++ = (unsigned char) ((toktype>>8)&0xff); + *ptr++ = (unsigned char) (toktype&0xff); /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */ krb5_hdr = ptr - 2; @@ -137,7 +140,7 @@ krb5_make_token(struct krb5_ctx *ctx, in /* XXX removing support for now */ goto out_err; } else { /* Sign only. */ - if (krb5_make_checksum(checksum_type, krb5_hdr, text, + if (make_checksum(checksum_type, krb5_hdr, 8, text, &md5cksum)) goto out_err; } @@ -151,7 +154,7 @@ krb5_make_token(struct krb5_ctx *ctx, in md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, KRB5_CKSUM_LENGTH); - dprintk("make_seal_token: cksum data: \n"); + dprintk("RPC: make_seal_token: cksum data: \n"); print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0); break; default: diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_seqnum.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_seqnum.c --- linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_seqnum.c 2004-05-09 22:32:26.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_seqnum.c 2004-05-17 15:16:07.000000000 -0400 @@ -70,7 +70,7 @@ krb5_get_seq_num(struct crypto_tfm *key, s32 code; unsigned char plain[8]; - dprintk("krb5_get_seq_num: \n"); + dprintk("RPC: krb5_get_seq_num:\n"); if ((code = krb5_decrypt(key, cksum, buf, plain, 8))) return code; diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_unseal.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_unseal.c --- linux-2.6.6/net/sunrpc/auth_gss/gss_krb5_unseal.c 2004-05-09 22:33:13.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_krb5_unseal.c 2004-05-17 15:16:41.000000000 -0400 @@ -99,6 +99,10 @@ krb5_read_token(struct krb5_ctx *ctx, if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr, toktype, read_token->len)) goto out; + + if ((*ptr++ != ((toktype>>8)&0xff)) || (*ptr++ != (toktype&0xff))) + goto out; + /* XXX sanity-check bodysize?? */ if (toktype == KG_TOK_WRAP_MSG) { @@ -149,7 +153,7 @@ krb5_read_token(struct krb5_ctx *ctx, switch (signalg) { case SGN_ALG_DES_MAC_MD5: - ret = krb5_make_checksum(checksum_type, ptr - 2, + ret = make_checksum(checksum_type, ptr - 2, 8, message_buffer, &md5cksum); if (ret) goto out; @@ -174,7 +178,7 @@ krb5_read_token(struct krb5_ctx *ctx, if (qop_state) *qop_state = GSS_C_QOP_DEFAULT; - now = jiffies; + now = get_seconds(); ret = GSS_S_CONTEXT_EXPIRED; if (now > ctx->endtime) diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/gss_mech_switch.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_mech_switch.c --- linux-2.6.6/net/sunrpc/auth_gss/gss_mech_switch.c 2004-05-09 22:32:52.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_mech_switch.c 2004-05-17 15:16:26.000000000 -0400 @@ -36,9 +36,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -51,146 +53,186 @@ static LIST_HEAD(registered_mechs); static spinlock_t registered_mechs_lock = SPIN_LOCK_UNLOCKED; -/* Reference counting: The reference count includes the reference in the - * global registered_mechs list. That reference will never diseappear - * (so the reference count will never go below 1) until after the mech - * is removed from the list. Nothing can be removed from the list without - * first getting the registered_mechs_lock, so a gss_api_mech won't diseappear - * from underneath us while we hold the registered_mech_lock. */ - -int -gss_mech_register(struct xdr_netobj * mech_type, struct gss_api_ops * ops) +static void +gss_mech_free(struct gss_api_mech *gm) { - struct gss_api_mech *gm; + struct pf_desc *pf; + int i; - if (!(gm = kmalloc(sizeof(*gm), GFP_KERNEL))) { - printk("Failed to allocate memory in gss_mech_register"); - return -1; - } - gm->gm_oid.len = mech_type->len; - if (!(gm->gm_oid.data = kmalloc(mech_type->len, GFP_KERNEL))) { - kfree(gm); - printk("Failed to allocate memory in gss_mech_register"); - return -1; - } - memcpy(gm->gm_oid.data, mech_type->data, mech_type->len); - /* We're counting the reference in the registered_mechs list: */ - atomic_set(&gm->gm_count, 1); - gm->gm_ops = ops; - - spin_lock(®istered_mechs_lock); - list_add(&gm->gm_list, ®istered_mechs); - spin_unlock(®istered_mechs_lock); - dprintk("RPC: gss_mech_register: registered mechanism with oid:\n"); - print_hexl((u32 *)mech_type->data, mech_type->len, 0); - return 0; + for (i = 0; i < gm->gm_pf_num; i++) { + pf = &gm->gm_pfs[i]; + if (pf->auth_domain_name) + kfree(pf->auth_domain_name); + pf->auth_domain_name = NULL; + } } -/* The following must be called with spinlock held: */ -int -do_gss_mech_unregister(struct gss_api_mech *gm) +static inline char * +make_auth_domain_name(char *name) { + static char *prefix = "gss/"; + char *new; - list_del(&gm->gm_list); + new = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL); + if (new) { + strcpy(new, prefix); + strcat(new, name); + } + return new; +} - dprintk("RPC: unregistered mechanism with oid:\n"); - print_hexl((u32 *)gm->gm_oid.data, gm->gm_oid.len, 0); - if (!gss_mech_put(gm)) { - dprintk("RPC: We just unregistered a gss_mechanism which" - " someone is still using.\n"); - return -1; - } else { - return 0; +static int +gss_mech_svc_setup(struct gss_api_mech *gm) +{ + struct pf_desc *pf; + int i, status; + + for (i = 0; i < gm->gm_pf_num; i++) { + pf = &gm->gm_pfs[i]; + pf->auth_domain_name = make_auth_domain_name(pf->name); + status = -ENOMEM; + if (pf->auth_domain_name == NULL) + goto out; + status = svcauth_gss_register_pseudoflavor(pf->pseudoflavor, + pf->auth_domain_name); + if (status) + goto out; } + return 0; +out: + gss_mech_free(gm); + return status; } int -gss_mech_unregister(struct gss_api_mech *gm) +gss_mech_register(struct gss_api_mech *gm) { int status; + status = gss_mech_svc_setup(gm); + if (status) + return status; spin_lock(®istered_mechs_lock); - status = do_gss_mech_unregister(gm); + list_add(&gm->gm_list, ®istered_mechs); spin_unlock(®istered_mechs_lock); - return status; + dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); + return 0; } -int -gss_mech_unregister_all(void) -{ - struct list_head *pos; - struct gss_api_mech *gm; - int status = 0; +EXPORT_SYMBOL(gss_mech_register); +void +gss_mech_unregister(struct gss_api_mech *gm) +{ spin_lock(®istered_mechs_lock); - while (!list_empty(®istered_mechs)) { - pos = registered_mechs.next; - gm = list_entry(pos, struct gss_api_mech, gm_list); - if (do_gss_mech_unregister(gm)) - status = -1; - } + list_del(&gm->gm_list); spin_unlock(®istered_mechs_lock); - return status; + dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); + gss_mech_free(gm); } +EXPORT_SYMBOL(gss_mech_unregister); + struct gss_api_mech * gss_mech_get(struct gss_api_mech *gm) { - atomic_inc(&gm->gm_count); + __module_get(gm->gm_owner); return gm; } +EXPORT_SYMBOL(gss_mech_get); + struct gss_api_mech * -gss_mech_get_by_OID(struct xdr_netobj *mech_type) +gss_mech_get_by_name(char *name) { - struct gss_api_mech *pos, *gm = NULL; + struct gss_api_mech *pos, *gm = NULL; - dprintk("RPC: gss_mech_get_by_OID searching for mechanism with OID:\n"); - print_hexl((u32 *)mech_type->data, mech_type->len, 0); spin_lock(®istered_mechs_lock); list_for_each_entry(pos, ®istered_mechs, gm_list) { - if ((pos->gm_oid.len == mech_type->len) - && !memcmp(pos->gm_oid.data, mech_type->data, - mech_type->len)) { - gm = gss_mech_get(pos); + if (0 == strcmp(name, pos->gm_name)) { + if (!try_module_get(pos->gm_owner)) + continue; + gm = pos; break; } } spin_unlock(®istered_mechs_lock); - dprintk("RPC: gss_mech_get_by_OID %s it\n", gm ? "found" : "didn't find"); return gm; + +} + +EXPORT_SYMBOL(gss_mech_get_by_name); + +static inline int +mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) +{ + int i; + + for (i = 0; i < gm->gm_pf_num; i++) { + if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) + return 1; + } + return 0; } struct gss_api_mech * -gss_mech_get_by_name(char *name) +gss_mech_get_by_pseudoflavor(u32 pseudoflavor) { - struct gss_api_mech *pos, *gm = NULL; + struct gss_api_mech *pos, *gm = NULL; spin_lock(®istered_mechs_lock); list_for_each_entry(pos, ®istered_mechs, gm_list) { - if (0 == strcmp(name, pos->gm_ops->name)) { - gm = gss_mech_get(pos); - break; + if (!try_module_get(pos->gm_owner)) + continue; + if (!mech_supports_pseudoflavor(pos, pseudoflavor)) { + module_put(pos->gm_owner); + continue; } + gm = pos; + break; } spin_unlock(®istered_mechs_lock); return gm; +} + +EXPORT_SYMBOL(gss_mech_get_by_pseudoflavor); +u32 +gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) +{ + int i; + + for (i = 0; i < gm->gm_pf_num; i++) { + if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) + return gm->gm_pfs[i].service; + } + return 0; } -int -gss_mech_put(struct gss_api_mech * gm) +EXPORT_SYMBOL(gss_pseudoflavor_to_service); + +char * +gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) { - if (atomic_dec_and_test(&gm->gm_count)) { - if (gm->gm_oid.len >0) - kfree(gm->gm_oid.data); - kfree(gm); - return 1; - } else { - return 0; + int i; + + for (i = 0; i < gm->gm_pf_num; i++) { + if (gm->gm_pfs[i].service == service) + return gm->gm_pfs[i].auth_domain_name; } + return NULL; } +EXPORT_SYMBOL(gss_service_to_auth_domain_name); + +void +gss_mech_put(struct gss_api_mech * gm) +{ + module_put(gm->gm_owner); +} + +EXPORT_SYMBOL(gss_mech_put); + /* The mech could probably be determined from the token instead, but it's just * as easy for now to pass it in. */ u32 @@ -244,7 +286,8 @@ gss_verify_mic(struct gss_ctx *context_ u32 gss_delete_sec_context(struct gss_ctx **context_handle) { - dprintk("gss_delete_sec_context deleting %p\n",*context_handle); + dprintk("RPC: gss_delete_sec_context deleting %p\n", + *context_handle); if (!*context_handle) return(GSS_S_NO_CONTEXT); diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/gss_pseudoflavors.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_pseudoflavors.c --- linux-2.6.6/net/sunrpc/auth_gss/gss_pseudoflavors.c 2004-05-09 22:32:37.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/gss_pseudoflavors.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,236 +0,0 @@ -/* - * linux/net/sunrpc/gss_union.c - * - * Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic code - * - * Copyright (c) 2001 The Regents of the University of Michigan. - * All rights reserved. - * - * Andy Adamson - * - */ - -/* - * Copyright 1993 by OpenVision Technologies, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appears in all copies and - * that both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of OpenVision not be used - * in advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. OpenVision makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#ifdef RPC_DEBUG -# define RPCDBG_FACILITY RPCDBG_AUTH -#endif - -static LIST_HEAD(registered_triples); -static spinlock_t registered_triples_lock = SPIN_LOCK_UNLOCKED; - -/* The following must be called with spinlock held: */ -static struct sup_sec_triple * -do_lookup_triple_by_pseudoflavor(u32 pseudoflavor) -{ - struct sup_sec_triple *pos, *triple = NULL; - - list_for_each_entry(pos, ®istered_triples, triples) { - if (pos->pseudoflavor == pseudoflavor) { - triple = pos; - break; - } - } - return triple; -} - -/* XXX Need to think about reference counting of triples and of mechs. - * Currently we do no reference counting of triples, and I think that's - * probably OK given the reference counting on mechs, but there's probably - * a better way to do all this. */ - -int -gss_register_triple(u32 pseudoflavor, struct gss_api_mech *mech, - u32 qop, u32 service) -{ - struct sup_sec_triple *triple; - - if (!(triple = kmalloc(sizeof(*triple), GFP_KERNEL))) { - printk("Alloc failed in gss_register_triple"); - goto err; - } - triple->pseudoflavor = pseudoflavor; - triple->mech = gss_mech_get_by_OID(&mech->gm_oid); - triple->qop = qop; - triple->service = service; - - spin_lock(®istered_triples_lock); - if (do_lookup_triple_by_pseudoflavor(pseudoflavor)) { - printk("Registered pseudoflavor %d again\n", pseudoflavor); - goto err_unlock; - } - list_add(&triple->triples, ®istered_triples); - spin_unlock(®istered_triples_lock); - dprintk("RPC: registered pseudoflavor %d\n", pseudoflavor); - - return 0; - -err_unlock: - kfree(triple); - spin_unlock(®istered_triples_lock); -err: - return -1; -} - -int -gss_unregister_triple(u32 pseudoflavor) -{ - struct sup_sec_triple *triple; - - spin_lock(®istered_triples_lock); - if (!(triple = do_lookup_triple_by_pseudoflavor(pseudoflavor))) { - spin_unlock(®istered_triples_lock); - printk("Can't unregister unregistered pseudoflavor %d\n", - pseudoflavor); - return -1; - } - list_del(&triple->triples); - spin_unlock(®istered_triples_lock); - gss_mech_put(triple->mech); - kfree(triple); - return 0; - -} - -void -print_sec_triple(struct xdr_netobj *oid,u32 qop,u32 service) -{ - dprintk("RPC: print_sec_triple:\n"); - dprintk(" oid_len %d\n oid :\n",oid->len); - print_hexl((u32 *)oid->data,oid->len,0); - dprintk(" qop %d\n",qop); - dprintk(" service %d\n",service); -} - -/* Function: gss_get_cmp_triples - * - * Description: search sec_triples for a matching security triple - * return pseudoflavor if match, else 0 - * (Note that 0 is a valid pseudoflavor, but not for any gss pseudoflavor - * (0 means auth_null), so this shouldn't cause confusion.) - */ -u32 -gss_cmp_triples(u32 oid_len, char *oid_data, u32 qop, u32 service) -{ - struct sup_sec_triple *triple; - u32 pseudoflavor = 0; - struct xdr_netobj oid; - - oid.len = oid_len; - oid.data = oid_data; - - dprintk("RPC: gss_cmp_triples \n"); - print_sec_triple(&oid,qop,service); - - spin_lock(®istered_triples_lock); - list_for_each_entry(triple, ®istered_triples, triples) { - if((g_OID_equal(&oid, &triple->mech->gm_oid)) - && (qop == triple->qop) - && (service == triple->service)) { - pseudoflavor = triple->pseudoflavor; - break; - } - } - spin_unlock(®istered_triples_lock); - dprintk("RPC: gss_cmp_triples return %d\n", pseudoflavor); - return pseudoflavor; -} - -u32 -gss_get_pseudoflavor(struct gss_ctx *ctx, u32 qop, u32 service) -{ - return gss_cmp_triples(ctx->mech_type->gm_oid.len, - ctx->mech_type->gm_oid.data, - qop, service); -} - -/* Returns nonzero iff the given pseudoflavor is in the supported list. - * (Note that without incrementing a reference count or anything, this - * doesn't give any guarantees.) */ -int -gss_pseudoflavor_supported(u32 pseudoflavor) -{ - struct sup_sec_triple *triple; - - spin_lock(®istered_triples_lock); - triple = do_lookup_triple_by_pseudoflavor(pseudoflavor); - spin_unlock(®istered_triples_lock); - return (triple ? 1 : 0); -} - -u32 -gss_pseudoflavor_to_service(u32 pseudoflavor) -{ - struct sup_sec_triple *triple; - - spin_lock(®istered_triples_lock); - triple = do_lookup_triple_by_pseudoflavor(pseudoflavor); - spin_unlock(®istered_triples_lock); - if (!triple) { - dprintk("RPC: gss_pseudoflavor_to_service called with" - " unsupported pseudoflavor %d\n", pseudoflavor); - return 0; - } - return triple->service; -} - -struct gss_api_mech * -gss_pseudoflavor_to_mech(u32 pseudoflavor) { - struct sup_sec_triple *triple; - struct gss_api_mech *mech = NULL; - - spin_lock(®istered_triples_lock); - triple = do_lookup_triple_by_pseudoflavor(pseudoflavor); - spin_unlock(®istered_triples_lock); - if (triple) - mech = gss_mech_get(triple->mech); - else - dprintk("RPC: gss_pseudoflavor_to_mech called with" - " unsupported pseudoflavor %d\n", pseudoflavor); - return mech; -} - -int -gss_pseudoflavor_to_mechOID(u32 pseudoflavor, struct xdr_netobj * oid) -{ - struct gss_api_mech *mech; - - mech = gss_pseudoflavor_to_mech(pseudoflavor); - if (!mech) { - dprintk("RPC: gss_pseudoflavor_to_mechOID called with" - " unsupported pseudoflavor %d\n", pseudoflavor); - return -1; - } - oid->len = mech->gm_oid.len; - if (!(oid->data = kmalloc(oid->len, GFP_KERNEL))) - return -1; - memcpy(oid->data, mech->gm_oid.data, oid->len); - gss_mech_put(mech); - return 0; -} diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/sunrpcgss_syms.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/sunrpcgss_syms.c --- linux-2.6.6/net/sunrpc/auth_gss/sunrpcgss_syms.c 2004-05-09 22:32:54.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/sunrpcgss_syms.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,35 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/* sec_triples: */ -EXPORT_SYMBOL(gss_register_triple); -EXPORT_SYMBOL(gss_unregister_triple); -EXPORT_SYMBOL(gss_cmp_triples); -EXPORT_SYMBOL(gss_pseudoflavor_to_mechOID); -EXPORT_SYMBOL(gss_pseudoflavor_supported); -EXPORT_SYMBOL(gss_pseudoflavor_to_service); -EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor); - -/* registering gss mechanisms to the mech switching code: */ -EXPORT_SYMBOL(gss_mech_register); -EXPORT_SYMBOL(gss_mech_get); -EXPORT_SYMBOL(gss_mech_get_by_OID); -EXPORT_SYMBOL(gss_mech_put); - -/* generic functionality in gss code: */ -EXPORT_SYMBOL(g_make_token_header); -EXPORT_SYMBOL(g_verify_token_header); -EXPORT_SYMBOL(g_token_size); - -/* debug */ -EXPORT_SYMBOL(print_hexl); diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/auth_gss/svcauth_gss.c linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/svcauth_gss.c --- linux-2.6.6/net/sunrpc/auth_gss/svcauth_gss.c 2004-05-09 22:32:29.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/auth_gss/svcauth_gss.c 2004-05-17 15:16:26.000000000 -0400 @@ -570,14 +570,14 @@ gss_verify_header(struct svc_rqst *rqstp } if (gc->gc_seq > MAXSEQ) { - dprintk("svcauth_gss: discarding request with large" - " sequence number %d\n", gc->gc_seq); + dprintk("RPC: svcauth_gss: discarding request with large sequence number %d\n", + gc->gc_seq); *authp = rpcsec_gsserr_ctxproblem; return SVC_DENIED; } if (!gss_check_seq_num(rsci, gc->gc_seq)) { - dprintk("svcauth_gss: discarding request with old" - " sequence number %d\n", gc->gc_seq); + dprintk("RPC: svcauth_gss: discarding request with old sequence number %d\n", + gc->gc_seq); return SVC_DROP; } return SVC_OK; @@ -617,19 +617,15 @@ struct gss_domain { u32 pseudoflavor; }; -/* XXX this should be done in gss_pseudoflavors, and shouldn't be hardcoded: */ static struct auth_domain * find_gss_auth_domain(struct gss_ctx *ctx, u32 svc) { - switch(gss_get_pseudoflavor(ctx, 0, svc)) { - case RPC_AUTH_GSS_KRB5: - return auth_domain_find("gss/krb5"); - case RPC_AUTH_GSS_KRB5I: - return auth_domain_find("gss/krb5i"); - case RPC_AUTH_GSS_KRB5P: - return auth_domain_find("gss/krb5p"); - } - return NULL; + char *name; + + name = gss_service_to_auth_domain_name(ctx->mech_type, svc); + if (!name) + return NULL; + return auth_domain_find(name); } int @@ -637,19 +633,17 @@ svcauth_gss_register_pseudoflavor(u32 ps { struct gss_domain *new; struct auth_domain *test; - static char *prefix = "gss/"; - int stat = -1; + int stat = -ENOMEM; new = kmalloc(sizeof(*new), GFP_KERNEL); if (!new) goto out; cache_init(&new->h.h); atomic_inc(&new->h.h.refcnt); - new->h.name = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL); + new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL); if (!new->h.name) goto out_free_dom; - strcpy(new->h.name, prefix); - strcat(new->h.name, name); + strcpy(new->h.name, name); new->h.flavour = RPC_AUTH_GSS; new->pseudoflavor = pseudoflavor; new->h.h.expiry_time = NEVER; @@ -670,6 +664,8 @@ out: return stat; } +EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor); + static inline int read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) { @@ -755,7 +751,7 @@ svcauth_gss_accept(struct svc_rqst *rqst u32 *reject_stat = resv->iov_base + resv->iov_len; int ret; - dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n",argv->iov_len); + dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n",argv->iov_len); *authp = rpc_autherr_badcred; if (!svcdata) diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/clnt.c linux-2.6.6-18-file_ctx2/net/sunrpc/clnt.c --- linux-2.6.6/net/sunrpc/clnt.c 2004-05-09 22:32:28.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/clnt.c 2004-05-17 15:17:02.000000000 -0400 @@ -351,7 +351,9 @@ int rpc_call_sync(struct rpc_clnt *clnt, rpc_clnt_sigmask(clnt, &oldset); /* Create/initialize a new RPC task */ - rpc_init_task(task, clnt, NULL, flags); + task = rpc_new_task(clnt, NULL, flags); + if (task == NULL) + return -ENOMEM; rpc_call_setup(task, msg, 0); /* Set up the call info struct and execute the task */ @@ -788,13 +790,11 @@ static void call_timeout(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - struct rpc_timeout *to = &task->tk_rqstp->rq_timeout; - if (xprt_adjust_timeout(to)) { + if (xprt_adjust_timeout(task->tk_rqstp) == 0) { 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)\n", task->tk_pid); if (RPC_IS_SOFT(task)) { diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/sched.c linux-2.6.6-18-file_ctx2/net/sunrpc/sched.c --- linux-2.6.6/net/sunrpc/sched.c 2004-05-09 22:32:37.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/sched.c 2004-05-17 15:17:09.000000000 -0400 @@ -41,13 +41,7 @@ static mempool_t *rpc_buffer_mempool; static void __rpc_default_timer(struct rpc_task *task); static void rpciod_killall(void); - -/* - * When an asynchronous RPC task is activated within a bottom half - * handler, or while executing another RPC task, it is put on - * schedq, and rpciod is woken up. - */ -static RPC_WAITQ(schedq, "schedq"); +static void rpc_async_schedule(void *); /* * RPC tasks that create another task (e.g. for contacting the portmapper) @@ -68,26 +62,18 @@ static LIST_HEAD(all_tasks); /* * rpciod-related stuff */ -static DECLARE_WAIT_QUEUE_HEAD(rpciod_idle); -static DECLARE_COMPLETION(rpciod_killer); static DECLARE_MUTEX(rpciod_sema); static unsigned int rpciod_users; -static pid_t rpciod_pid; -static int rpc_inhibit; +static struct workqueue_struct *rpciod_workqueue; /* - * Spinlock for wait queues. Access to the latter also has to be - * interrupt-safe in order to allow timers to wake up sleeping tasks. - */ -static spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED; -/* * Spinlock for other critical sections of code. */ static spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED; /* * Disable the timer for a given RPC task. Should be called with - * rpc_queue_lock and bh_disabled in order to avoid races within + * queue->lock and bh_disabled in order to avoid races within * rpc_run_timer(). */ static inline void @@ -105,16 +91,13 @@ __rpc_disable_timer(struct rpc_task *tas * without calling del_timer_sync(). The latter could cause a * deadlock if called while we're holding spinlocks... */ -static void -rpc_run_timer(struct rpc_task *task) +static void rpc_run_timer(struct rpc_task *task) { void (*callback)(struct rpc_task *); - spin_lock_bh(&rpc_queue_lock); callback = task->tk_timeout_fn; task->tk_timeout_fn = NULL; - spin_unlock_bh(&rpc_queue_lock); - if (callback) { + if (callback && RPC_IS_QUEUED(task)) { dprintk("RPC: %4d running timer\n", task->tk_pid); callback(task); } @@ -140,19 +123,8 @@ __rpc_add_timer(struct rpc_task *task, r } /* - * Set up a timer for an already sleeping task. - */ -void rpc_add_timer(struct rpc_task *task, rpc_action timer) -{ - spin_lock_bh(&rpc_queue_lock); - if (!RPC_IS_RUNNING(task)) - __rpc_add_timer(task, timer); - spin_unlock_bh(&rpc_queue_lock); -} - -/* * Delete any timer for the current task. Because we use del_timer_sync(), - * this function should never be called while holding rpc_queue_lock. + * this function should never be called while holding queue->lock. */ static inline void rpc_delete_timer(struct rpc_task *task) @@ -169,16 +141,17 @@ static void __rpc_add_wait_queue_priorit struct list_head *q; struct rpc_task *t; + INIT_LIST_HEAD(&task->u.tk_wait.links); q = &queue->tasks[task->tk_priority]; if (unlikely(task->tk_priority > queue->maxpriority)) q = &queue->tasks[queue->maxpriority]; - list_for_each_entry(t, q, tk_list) { + list_for_each_entry(t, q, u.tk_wait.list) { if (t->tk_cookie == task->tk_cookie) { - list_add_tail(&task->tk_list, &t->tk_links); + list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links); return; } } - list_add_tail(&task->tk_list, q); + list_add_tail(&task->u.tk_wait.list, q); } /* @@ -189,37 +162,21 @@ static void __rpc_add_wait_queue_priorit * improve overall performance. * Everyone else gets appended to the queue to ensure proper FIFO behavior. */ -static int __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) +static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) { - if (task->tk_rpcwait == queue) - return 0; + BUG_ON (RPC_IS_QUEUED(task)); - if (task->tk_rpcwait) { - printk(KERN_WARNING "RPC: doubly enqueued task!\n"); - return -EWOULDBLOCK; - } if (RPC_IS_PRIORITY(queue)) __rpc_add_wait_queue_priority(queue, task); else if (RPC_IS_SWAPPER(task)) - list_add(&task->tk_list, &queue->tasks[0]); + list_add(&task->u.tk_wait.list, &queue->tasks[0]); else - list_add_tail(&task->tk_list, &queue->tasks[0]); - task->tk_rpcwait = queue; + list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); + task->u.tk_wait.rpc_waitq = queue; + rpc_set_queued(task); dprintk("RPC: %4d added to queue %p \"%s\"\n", task->tk_pid, queue, rpc_qname(queue)); - - return 0; -} - -int rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task) -{ - int result; - - spin_lock_bh(&rpc_queue_lock); - result = __rpc_add_wait_queue(q, task); - spin_unlock_bh(&rpc_queue_lock); - return result; } /* @@ -229,12 +186,12 @@ static void __rpc_remove_wait_queue_prio { struct rpc_task *t; - if (!list_empty(&task->tk_links)) { - t = list_entry(task->tk_links.next, struct rpc_task, tk_list); - list_move(&t->tk_list, &task->tk_list); - list_splice_init(&task->tk_links, &t->tk_links); + if (!list_empty(&task->u.tk_wait.links)) { + t = list_entry(task->u.tk_wait.links.next, struct rpc_task, u.tk_wait.list); + list_move(&t->u.tk_wait.list, &task->u.tk_wait.list); + list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links); } - list_del(&task->tk_list); + list_del(&task->u.tk_wait.list); } /* @@ -243,31 +200,17 @@ static void __rpc_remove_wait_queue_prio */ static void __rpc_remove_wait_queue(struct rpc_task *task) { - struct rpc_wait_queue *queue = task->tk_rpcwait; - - if (!queue) - return; + struct rpc_wait_queue *queue; + queue = task->u.tk_wait.rpc_waitq; if (RPC_IS_PRIORITY(queue)) __rpc_remove_wait_queue_priority(task); else - list_del(&task->tk_list); - task->tk_rpcwait = NULL; - + list_del(&task->u.tk_wait.list); dprintk("RPC: %4d removed from queue %p \"%s\"\n", task->tk_pid, queue, rpc_qname(queue)); } -void -rpc_remove_wait_queue(struct rpc_task *task) -{ - if (!task->tk_rpcwait) - return; - spin_lock_bh(&rpc_queue_lock); - __rpc_remove_wait_queue(task); - spin_unlock_bh(&rpc_queue_lock); -} - static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) { queue->priority = priority; @@ -290,6 +233,7 @@ static void __rpc_init_priority_wait_que { int i; + spin_lock_init(&queue->lock); for (i = 0; i < ARRAY_SIZE(queue->tasks); i++) INIT_LIST_HEAD(&queue->tasks[i]); queue->maxpriority = maxprio; @@ -316,34 +260,27 @@ EXPORT_SYMBOL(rpc_init_wait_queue); * Note: If the task is ASYNC, this must be called with * the spinlock held to protect the wait queue operation. */ -static inline void -rpc_make_runnable(struct rpc_task *task) +static void rpc_make_runnable(struct rpc_task *task) { - if (task->tk_timeout_fn) { - printk(KERN_ERR "RPC: task w/ running timer in rpc_make_runnable!!\n"); + if (rpc_test_and_set_running(task)) return; - } - rpc_set_running(task); + BUG_ON(task->tk_timeout_fn); if (RPC_IS_ASYNC(task)) { - if (RPC_IS_SLEEPING(task)) { - int status; - status = __rpc_add_wait_queue(&schedq, task); - if (status < 0) { - printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); - task->tk_status = status; - return; - } - rpc_clear_sleeping(task); - wake_up(&rpciod_idle); + int status; + + INIT_WORK(&task->u.tk_work, rpc_async_schedule, (void *)task); + status = queue_work(task->tk_workqueue, &task->u.tk_work); + if (status < 0) { + printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); + task->tk_status = status; + return; } - } else { - rpc_clear_sleeping(task); - wake_up(&task->tk_wait); - } + } else + wake_up(&task->u.tk_wait.waitq); } /* - * Place a newly initialized task on the schedq. + * Place a newly initialized task on the workqueue. */ static inline void rpc_schedule_run(struct rpc_task *task) @@ -352,33 +289,18 @@ rpc_schedule_run(struct rpc_task *task) if (RPC_IS_ACTIVATED(task)) return; task->tk_active = 1; - rpc_set_sleeping(task); rpc_make_runnable(task); } /* - * For other people who may need to wake the I/O daemon - * but should (for now) know nothing about its innards - */ -void rpciod_wake_up(void) -{ - if(rpciod_pid==0) - printk(KERN_ERR "rpciod: wot no daemon?\n"); - wake_up(&rpciod_idle); -} - -/* * Prepare for sleeping on a wait queue. * By always appending tasks to the list we ensure FIFO behavior. * NB: An RPC task will only receive interrupt-driven events as long * as it's on a wait queue. */ -static void -__rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, +static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, rpc_action action, rpc_action timer) { - int status; - dprintk("RPC: %4d sleep_on(queue \"%s\" time %ld)\n", task->tk_pid, rpc_qname(q), jiffies); @@ -388,49 +310,36 @@ __rpc_sleep_on(struct rpc_wait_queue *q, } /* Mark the task as being activated if so needed */ - if (!RPC_IS_ACTIVATED(task)) { + if (!RPC_IS_ACTIVATED(task)) task->tk_active = 1; - rpc_set_sleeping(task); - } - status = __rpc_add_wait_queue(q, task); - if (status) { - printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); - task->tk_status = status; - } else { - rpc_clear_running(task); - if (task->tk_callback) { - dprintk(KERN_ERR "RPC: %4d overwrites an active callback\n", task->tk_pid); - BUG(); - } - task->tk_callback = action; - __rpc_add_timer(task, timer); - } + __rpc_add_wait_queue(q, task); + + BUG_ON(task->tk_callback != NULL); + task->tk_callback = action; + __rpc_add_timer(task, timer); } -void -rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, +void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, rpc_action action, rpc_action timer) { /* * Protect the queue operations. */ - spin_lock_bh(&rpc_queue_lock); + spin_lock_bh(&q->lock); __rpc_sleep_on(q, task, action, timer); - spin_unlock_bh(&rpc_queue_lock); + spin_unlock_bh(&q->lock); } /** - * __rpc_wake_up_task - wake up a single rpc_task + * __rpc_do_wake_up_task - wake up a single rpc_task * @task: task to be woken up * - * Caller must hold rpc_queue_lock + * Caller must hold queue->lock, and have cleared the task queued flag. */ -static void -__rpc_wake_up_task(struct rpc_task *task) +static void __rpc_do_wake_up_task(struct rpc_task *task) { - dprintk("RPC: %4d __rpc_wake_up_task (now %ld inh %d)\n", - task->tk_pid, jiffies, rpc_inhibit); + dprintk("RPC: %4d __rpc_wake_up_task (now %ld)\n", task->tk_pid, jiffies); #ifdef RPC_DEBUG if (task->tk_magic != 0xf00baa) { @@ -445,12 +354,9 @@ __rpc_wake_up_task(struct rpc_task *task printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task); return; } - if (RPC_IS_RUNNING(task)) - return; __rpc_disable_timer(task); - if (task->tk_rpcwait != &schedq) - __rpc_remove_wait_queue(task); + __rpc_remove_wait_queue(task); rpc_make_runnable(task); @@ -458,6 +364,15 @@ __rpc_wake_up_task(struct rpc_task *task } /* + * Wake up the specified task + */ +static void __rpc_wake_up_task(struct rpc_task *task) +{ + if (rpc_test_and_clear_queued(task)) + __rpc_do_wake_up_task(task); +} + +/* * Default timeout handler if none specified by user */ static void @@ -471,14 +386,15 @@ __rpc_default_timer(struct rpc_task *tas /* * Wake up the specified task */ -void -rpc_wake_up_task(struct rpc_task *task) +void rpc_wake_up_task(struct rpc_task *task) { - if (RPC_IS_RUNNING(task)) - return; - spin_lock_bh(&rpc_queue_lock); - __rpc_wake_up_task(task); - spin_unlock_bh(&rpc_queue_lock); + if (rpc_test_and_clear_queued(task)) { + struct rpc_wait_queue *queue = task->u.tk_wait.rpc_waitq; + + spin_lock_bh(&queue->lock); + __rpc_do_wake_up_task(task); + spin_unlock_bh(&queue->lock); + } } /* @@ -494,11 +410,11 @@ static struct rpc_task * __rpc_wake_up_n */ q = &queue->tasks[queue->priority]; if (!list_empty(q)) { - task = list_entry(q->next, struct rpc_task, tk_list); + task = list_entry(q->next, struct rpc_task, u.tk_wait.list); if (queue->cookie == task->tk_cookie) { if (--queue->nr) goto out; - list_move_tail(&task->tk_list, q); + list_move_tail(&task->u.tk_wait.list, q); } /* * Check if we need to switch queues. @@ -516,7 +432,7 @@ static struct rpc_task * __rpc_wake_up_n else q = q - 1; if (!list_empty(q)) { - task = list_entry(q->next, struct rpc_task, tk_list); + task = list_entry(q->next, struct rpc_task, u.tk_wait.list); goto new_queue; } } while (q != &queue->tasks[queue->priority]); @@ -541,14 +457,14 @@ struct rpc_task * rpc_wake_up_next(struc struct rpc_task *task = NULL; dprintk("RPC: wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue)); - spin_lock_bh(&rpc_queue_lock); + spin_lock_bh(&queue->lock); if (RPC_IS_PRIORITY(queue)) task = __rpc_wake_up_next_priority(queue); else { task_for_first(task, &queue->tasks[0]) __rpc_wake_up_task(task); } - spin_unlock_bh(&rpc_queue_lock); + spin_unlock_bh(&queue->lock); return task; } @@ -557,25 +473,25 @@ struct rpc_task * rpc_wake_up_next(struc * rpc_wake_up - wake up all rpc_tasks * @queue: rpc_wait_queue on which the tasks are sleeping * - * Grabs rpc_queue_lock + * Grabs queue->lock */ void rpc_wake_up(struct rpc_wait_queue *queue) { struct rpc_task *task; struct list_head *head; - spin_lock_bh(&rpc_queue_lock); + spin_lock_bh(&queue->lock); head = &queue->tasks[queue->maxpriority]; for (;;) { while (!list_empty(head)) { - task = list_entry(head->next, struct rpc_task, tk_list); + task = list_entry(head->next, struct rpc_task, u.tk_wait.list); __rpc_wake_up_task(task); } if (head == &queue->tasks[0]) break; head--; } - spin_unlock_bh(&rpc_queue_lock); + spin_unlock_bh(&queue->lock); } /** @@ -583,18 +499,18 @@ void rpc_wake_up(struct rpc_wait_queue * * @queue: rpc_wait_queue on which the tasks are sleeping * @status: status value to set * - * Grabs rpc_queue_lock + * Grabs queue->lock */ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) { struct list_head *head; struct rpc_task *task; - spin_lock_bh(&rpc_queue_lock); + spin_lock_bh(&queue->lock); head = &queue->tasks[queue->maxpriority]; for (;;) { while (!list_empty(head)) { - task = list_entry(head->next, struct rpc_task, tk_list); + task = list_entry(head->next, struct rpc_task, u.tk_wait.list); task->tk_status = status; __rpc_wake_up_task(task); } @@ -602,7 +518,7 @@ void rpc_wake_up_status(struct rpc_wait_ break; head--; } - spin_unlock_bh(&rpc_queue_lock); + spin_unlock_bh(&queue->lock); } /* @@ -626,18 +542,14 @@ __rpc_atrun(struct rpc_task *task) /* * This is the RPC `scheduler' (or rather, the finite state machine). */ -static int -__rpc_execute(struct rpc_task *task) +static int __rpc_execute(struct rpc_task *task) { int status = 0; dprintk("RPC: %4d rpc_execute flgs %x\n", task->tk_pid, task->tk_flags); - if (!RPC_IS_RUNNING(task)) { - printk(KERN_WARNING "RPC: rpc_execute called for sleeping task!!\n"); - return 0; - } + BUG_ON(RPC_IS_QUEUED(task)); restarted: while (1) { @@ -657,7 +569,9 @@ __rpc_execute(struct rpc_task *task) */ save_callback=task->tk_callback; task->tk_callback=NULL; + lock_kernel(); save_callback(task); + unlock_kernel(); } /* @@ -665,43 +579,41 @@ __rpc_execute(struct rpc_task *task) * tk_action may be NULL when the task has been killed * by someone else. */ - if (RPC_IS_RUNNING(task)) { + if (!RPC_IS_QUEUED(task)) { /* * Garbage collection of pending timers... */ rpc_delete_timer(task); if (!task->tk_action) break; + lock_kernel(); task->tk_action(task); - /* micro-optimization to avoid spinlock */ - if (RPC_IS_RUNNING(task)) - continue; + unlock_kernel(); } /* - * Check whether task is sleeping. + * Lockless check for whether task is sleeping or not. */ - spin_lock_bh(&rpc_queue_lock); - if (!RPC_IS_RUNNING(task)) { - rpc_set_sleeping(task); - if (RPC_IS_ASYNC(task)) { - spin_unlock_bh(&rpc_queue_lock); + if (!RPC_IS_QUEUED(task)) + continue; + if (RPC_IS_ASYNC(task)) { + rpc_clear_running(task); + /* Careful! we may have raced... */ + if (RPC_IS_QUEUED(task)) return 0; - } + if (rpc_test_and_set_running(task)) + return 0; + continue; } - spin_unlock_bh(&rpc_queue_lock); - if (!RPC_IS_SLEEPING(task)) - continue; + init_waitqueue_head(&task->u.tk_wait.waitq); + rpc_clear_running(task); /* sync task: sleep here */ dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid); - if (current->pid == rpciod_pid) - printk(KERN_ERR "RPC: rpciod waiting on sync task!\n"); - if (!task->tk_client->cl_intr) { - __wait_event(task->tk_wait, !RPC_IS_SLEEPING(task)); + __wait_event(task->u.tk_wait.waitq, RPC_IS_RUNNING(task)); } else { - __wait_event_interruptible(task->tk_wait, !RPC_IS_SLEEPING(task), status); + __wait_event_interruptible(task->u.tk_wait.waitq, RPC_IS_RUNNING(task), status); /* * When a sync task receives a signal, it exits with * -ERESTARTSYS. In order to catch any callbacks that @@ -719,7 +631,9 @@ __rpc_execute(struct rpc_task *task) } if (task->tk_exit) { + lock_kernel(); task->tk_exit(task); + unlock_kernel(); /* If tk_action is non-null, the user wants us to restart */ if (task->tk_action) { if (!RPC_ASSASSINATED(task)) { @@ -738,7 +652,6 @@ __rpc_execute(struct rpc_task *task) /* Release all resources associated with the task */ rpc_release_task(task); - return status; } @@ -754,57 +667,16 @@ __rpc_execute(struct rpc_task *task) int rpc_execute(struct rpc_task *task) { - int status = -EIO; - if (rpc_inhibit) { - printk(KERN_INFO "RPC: execution inhibited!\n"); - goto out_release; - } - - status = -EWOULDBLOCK; - if (task->tk_active) { - printk(KERN_ERR "RPC: active task was run twice!\n"); - goto out_err; - } + BUG_ON(task->tk_active); task->tk_active = 1; rpc_set_running(task); return __rpc_execute(task); - out_release: - rpc_release_task(task); - out_err: - return status; } -/* - * This is our own little scheduler for async RPC tasks. - */ -static void -__rpc_schedule(void) +static void rpc_async_schedule(void *arg) { - struct rpc_task *task; - int count = 0; - - dprintk("RPC: rpc_schedule enter\n"); - while (1) { - - task_for_first(task, &schedq.tasks[0]) { - __rpc_remove_wait_queue(task); - spin_unlock_bh(&rpc_queue_lock); - - __rpc_execute(task); - spin_lock_bh(&rpc_queue_lock); - } else { - break; - } - - if (++count >= 200 || need_resched()) { - count = 0; - spin_unlock_bh(&rpc_queue_lock); - schedule(); - spin_lock_bh(&rpc_queue_lock); - } - } - dprintk("RPC: rpc_schedule leave\n"); + __rpc_execute((struct rpc_task *)arg); } /* @@ -862,7 +734,6 @@ void rpc_init_task(struct rpc_task *task task->tk_client = clnt; task->tk_flags = flags; task->tk_exit = callback; - init_waitqueue_head(&task->tk_wait); if (current->uid != current->fsuid || current->gid != current->fsgid) task->tk_flags |= RPC_TASK_SETUID; @@ -873,7 +744,9 @@ void rpc_init_task(struct rpc_task *task task->tk_priority = RPC_PRIORITY_NORMAL; task->tk_cookie = (unsigned long)current; - INIT_LIST_HEAD(&task->tk_links); + + /* Initialize workqueue for async tasks */ + task->tk_workqueue = rpciod_workqueue; /* Add to global list of all tasks */ spin_lock(&rpc_sched_lock); @@ -942,8 +815,7 @@ cleanup: goto out; } -void -rpc_release_task(struct rpc_task *task) +void rpc_release_task(struct rpc_task *task) { dprintk("RPC: %4d release task\n", task->tk_pid); @@ -961,19 +833,9 @@ rpc_release_task(struct rpc_task *task) list_del(&task->tk_task); spin_unlock(&rpc_sched_lock); - /* Protect the execution below. */ - spin_lock_bh(&rpc_queue_lock); - - /* Disable timer to prevent zombie wakeup */ - __rpc_disable_timer(task); - - /* Remove from any wait queue we're still on */ - __rpc_remove_wait_queue(task); - + BUG_ON (rpc_test_and_clear_queued(task)); task->tk_active = 0; - spin_unlock_bh(&rpc_queue_lock); - /* Synchronously delete any running timer */ rpc_delete_timer(task); @@ -1003,10 +865,9 @@ rpc_release_task(struct rpc_task *task) * queue 'childq'. If so returns a pointer to the parent. * Upon failure returns NULL. * - * Caller must hold rpc_queue_lock + * Caller must hold childq.lock */ -static inline struct rpc_task * -rpc_find_parent(struct rpc_task *child) +static inline struct rpc_task *rpc_find_parent(struct rpc_task *child) { struct rpc_task *task, *parent; struct list_head *le; @@ -1019,17 +880,16 @@ rpc_find_parent(struct rpc_task *child) return NULL; } -static void -rpc_child_exit(struct rpc_task *child) +static void rpc_child_exit(struct rpc_task *child) { struct rpc_task *parent; - spin_lock_bh(&rpc_queue_lock); + spin_lock_bh(&childq.lock); if ((parent = rpc_find_parent(child)) != NULL) { parent->tk_status = child->tk_status; __rpc_wake_up_task(parent); } - spin_unlock_bh(&rpc_queue_lock); + spin_unlock_bh(&childq.lock); } /* @@ -1052,22 +912,20 @@ fail: return NULL; } -void -rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func) +void rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func) { - spin_lock_bh(&rpc_queue_lock); + spin_lock_bh(&childq.lock); /* N.B. Is it possible for the child to have already finished? */ __rpc_sleep_on(&childq, task, func, NULL); rpc_schedule_run(child); - spin_unlock_bh(&rpc_queue_lock); + spin_unlock_bh(&childq.lock); } /* * Kill all tasks for the given client. * XXX: kill their descendants as well? */ -void -rpc_killall_tasks(struct rpc_clnt *clnt) +void rpc_killall_tasks(struct rpc_clnt *clnt) { struct rpc_task *rovr; struct list_head *le; @@ -1089,93 +947,14 @@ rpc_killall_tasks(struct rpc_clnt *clnt) static DECLARE_MUTEX_LOCKED(rpciod_running); -static inline int -rpciod_task_pending(void) -{ - return !list_empty(&schedq.tasks[0]); -} - - -/* - * This is the rpciod kernel thread - */ -static int -rpciod(void *ptr) -{ - int rounds = 0; - - lock_kernel(); - /* - * Let our maker know we're running ... - */ - rpciod_pid = current->pid; - up(&rpciod_running); - - daemonize("rpciod"); - allow_signal(SIGKILL); - - dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid); - spin_lock_bh(&rpc_queue_lock); - while (rpciod_users) { - DEFINE_WAIT(wait); - if (signalled()) { - spin_unlock_bh(&rpc_queue_lock); - rpciod_killall(); - flush_signals(current); - spin_lock_bh(&rpc_queue_lock); - } - __rpc_schedule(); - if (current->flags & PF_FREEZE) { - spin_unlock_bh(&rpc_queue_lock); - refrigerator(PF_FREEZE); - spin_lock_bh(&rpc_queue_lock); - } - - if (++rounds >= 64) { /* safeguard */ - spin_unlock_bh(&rpc_queue_lock); - schedule(); - rounds = 0; - spin_lock_bh(&rpc_queue_lock); - } - - dprintk("RPC: rpciod back to sleep\n"); - prepare_to_wait(&rpciod_idle, &wait, TASK_INTERRUPTIBLE); - if (!rpciod_task_pending() && !signalled()) { - spin_unlock_bh(&rpc_queue_lock); - schedule(); - rounds = 0; - spin_lock_bh(&rpc_queue_lock); - } - finish_wait(&rpciod_idle, &wait); - dprintk("RPC: switch to rpciod\n"); - } - spin_unlock_bh(&rpc_queue_lock); - - dprintk("RPC: rpciod shutdown commences\n"); - if (!list_empty(&all_tasks)) { - printk(KERN_ERR "rpciod: active tasks at shutdown?!\n"); - rpciod_killall(); - } - - dprintk("RPC: rpciod exiting\n"); - unlock_kernel(); - - rpciod_pid = 0; - complete_and_exit(&rpciod_killer, 0); - return 0; -} - -static void -rpciod_killall(void) +static void rpciod_killall(void) { unsigned long flags; while (!list_empty(&all_tasks)) { clear_thread_flag(TIF_SIGPENDING); rpc_killall_tasks(NULL); - spin_lock_bh(&rpc_queue_lock); - __rpc_schedule(); - spin_unlock_bh(&rpc_queue_lock); + flush_workqueue(rpciod_workqueue); if (!list_empty(&all_tasks)) { dprintk("rpciod_killall: waiting for tasks to exit\n"); yield(); @@ -1193,28 +972,30 @@ rpciod_killall(void) int rpciod_up(void) { + struct workqueue_struct *wq; int error = 0; down(&rpciod_sema); - dprintk("rpciod_up: pid %d, users %d\n", rpciod_pid, rpciod_users); + dprintk("rpciod_up: users %d\n", rpciod_users); rpciod_users++; - if (rpciod_pid) + if (rpciod_workqueue) goto out; /* * If there's no pid, we should be the first user. */ if (rpciod_users > 1) - printk(KERN_WARNING "rpciod_up: no pid, %d users??\n", rpciod_users); + printk(KERN_WARNING "rpciod_up: no workqueue, %d users??\n", rpciod_users); /* * Create the rpciod thread and wait for it to start. */ - error = kernel_thread(rpciod, NULL, 0); - if (error < 0) { - printk(KERN_WARNING "rpciod_up: create thread failed, error=%d\n", error); + error = -ENOMEM; + wq = create_workqueue("rpciod"); + if (wq == NULL) { + printk(KERN_WARNING "rpciod_up: create workqueue failed, error=%d\n", error); rpciod_users--; goto out; } - down(&rpciod_running); + rpciod_workqueue = wq; error = 0; out: up(&rpciod_sema); @@ -1225,20 +1006,21 @@ void rpciod_down(void) { down(&rpciod_sema); - dprintk("rpciod_down pid %d sema %d\n", rpciod_pid, rpciod_users); + dprintk("rpciod_down sema %d\n", rpciod_users); if (rpciod_users) { if (--rpciod_users) goto out; } else - printk(KERN_WARNING "rpciod_down: pid=%d, no users??\n", rpciod_pid); + printk(KERN_WARNING "rpciod_down: no users??\n"); - if (!rpciod_pid) { + if (!rpciod_workqueue) { dprintk("rpciod_down: Nothing to do!\n"); goto out; } + rpciod_killall(); - kill_proc(rpciod_pid, SIGKILL, 1); - wait_for_completion(&rpciod_killer); + destroy_workqueue(rpciod_workqueue); + rpciod_workqueue = NULL; out: up(&rpciod_sema); } @@ -1256,7 +1038,12 @@ void rpc_show_tasks(void) } printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout " "-rpcwait -action- --exit--\n"); - alltask_for_each(t, le, &all_tasks) + alltask_for_each(t, le, &all_tasks) { + const char *rpc_waitq = "none"; + + if (RPC_IS_QUEUED(t)) + rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq); + printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n", t->tk_pid, (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1), @@ -1264,8 +1051,9 @@ void rpc_show_tasks(void) t->tk_client, (t->tk_client ? t->tk_client->cl_prog : 0), t->tk_rqstp, t->tk_timeout, - rpc_qname(t->tk_rpcwait), + rpc_waitq, t->tk_action, t->tk_exit); + } spin_unlock(&rpc_sched_lock); } #endif diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/timer.c linux-2.6.6-18-file_ctx2/net/sunrpc/timer.c --- linux-2.6.6/net/sunrpc/timer.c 2004-05-09 22:33:14.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/timer.c 2004-05-17 15:15:53.000000000 -0400 @@ -39,6 +39,7 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigne for (i = 0; i < 5; i++) { rt->srtt[i] = init; rt->sdrtt[i] = RPC_RTO_INIT; + rt->ntimeouts[i] = 0; } } diff -u --recursive --new-file --show-c-function linux-2.6.6/net/sunrpc/xprt.c linux-2.6.6-18-file_ctx2/net/sunrpc/xprt.c --- linux-2.6.6/net/sunrpc/xprt.c 2004-05-09 22:32:53.000000000 -0400 +++ linux-2.6.6-18-file_ctx2/net/sunrpc/xprt.c 2004-05-17 15:17:02.000000000 -0400 @@ -352,35 +352,57 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, } /* + * Reset the major timeout value + */ +static void xprt_reset_majortimeo(struct rpc_rqst *req) +{ + struct rpc_timeout *to = &req->rq_xprt->timeout; + + req->rq_majortimeo = req->rq_timeout; + if (to->to_exponential) + req->rq_majortimeo <<= to->to_retries; + else + req->rq_majortimeo += to->to_increment * to->to_retries; + if (req->rq_majortimeo > to->to_maxval || req->rq_majortimeo == 0) + req->rq_majortimeo = to->to_maxval; + req->rq_majortimeo += jiffies; +} + +/* * Adjust timeout values etc for next retransmit */ -int -xprt_adjust_timeout(struct rpc_timeout *to) +int xprt_adjust_timeout(struct rpc_rqst *req) { - if (to->to_retries > 0) { + struct rpc_xprt *xprt = req->rq_xprt; + struct rpc_timeout *to = &xprt->timeout; + int status = 0; + + if (time_before(jiffies, req->rq_majortimeo)) { if (to->to_exponential) - to->to_current <<= 1; + req->rq_timeout <<= 1; else - to->to_current += to->to_increment; - if (to->to_maxval && to->to_current >= to->to_maxval) - to->to_current = to->to_maxval; + req->rq_timeout += to->to_increment; + if (to->to_maxval && req->rq_timeout >= to->to_maxval) + req->rq_timeout = to->to_maxval; + req->rq_retries++; + pprintk("RPC: %lu retrans\n", jiffies); } else { - if (to->to_exponential) - to->to_initval <<= 1; - else - to->to_initval += to->to_increment; - if (to->to_maxval && to->to_initval >= to->to_maxval) - to->to_initval = to->to_maxval; - to->to_current = to->to_initval; + req->rq_timeout = to->to_initval; + req->rq_retries = 0; + xprt_reset_majortimeo(req); + /* Reset the RTT counters == "slow start" */ + spin_lock_bh(&xprt->sock_lock); + rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval); + spin_unlock_bh(&xprt->sock_lock); + pprintk("RPC: %lu timeout\n", jiffies); + status = -ETIMEDOUT; } - if (!to->to_current) { - printk(KERN_WARNING "xprt_adjust_timeout: to_current = 0!\n"); - to->to_current = 5 * HZ; - } - pprintk("RPC: %lu %s\n", jiffies, - to->to_retries? "retrans" : "timeout"); - return to->to_retries-- > 0; + if (req->rq_timeout == 0) { + printk(KERN_WARNING "xprt_adjust_timeout: rq_timeout = 0!\n"); + req->rq_timeout = 5 * HZ; + } + return status; } /* @@ -537,8 +559,17 @@ void xprt_connect(struct rpc_task *task) task->tk_timeout = RPC_CONNECT_TIMEOUT; rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); - if (!test_and_set_bit(XPRT_CONNECTING, &xprt->sockstate)) - schedule_work(&xprt->sock_connect); + if (!test_and_set_bit(XPRT_CONNECTING, &xprt->sockstate)) { + /* Note: if we are here due to a dropped connection + * we delay reconnecting by RPC_REESTABLISH_TIMEOUT/HZ + * seconds + */ + if (xprt->sock != NULL) + schedule_delayed_work(&xprt->sock_connect, + RPC_REESTABLISH_TIMEOUT); + else + schedule_work(&xprt->sock_connect); + } return; out_write: xprt_release_write(xprt, task); @@ -566,7 +597,6 @@ xprt_connect_status(struct rpc_task *tas case -ECONNREFUSED: case -ECONNRESET: case -ENOTCONN: - rpc_delay(task, RPC_REESTABLISH_TIMEOUT); return; case -ETIMEDOUT: dprintk("RPC: %4d xprt_connect_status: timed out\n", @@ -1069,7 +1099,7 @@ xprt_write_space(struct sock *sk) goto out; spin_lock_bh(&xprt->sock_lock); - if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) + if (xprt->snd_task) rpc_wake_up_task(xprt->snd_task); spin_unlock_bh(&xprt->sock_lock); out: @@ -1166,6 +1196,7 @@ xprt_transmit(struct rpc_task *task) /* Add request to the receive list */ list_add_tail(&req->rq_list, &xprt->recv); spin_unlock_bh(&xprt->sock_lock); + xprt_reset_majortimeo(req); } } else if (!req->rq_bytes_sent) return; @@ -1221,7 +1252,7 @@ xprt_transmit(struct rpc_task *task) 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; + task->tk_timeout = req->rq_timeout; rpc_sleep_on(&xprt->pending, task, NULL, NULL); } spin_unlock_bh(&xprt->sock_lock); @@ -1248,13 +1279,11 @@ xprt_transmit(struct rpc_task *task) if (!xprt->nocong) { int timer = task->tk_msg.rpc_proc->p_timer; task->tk_timeout = rpc_calc_rto(clnt->cl_rtt, timer); - task->tk_timeout <<= rpc_ntimeo(clnt->cl_rtt, timer); - task->tk_timeout <<= clnt->cl_timeout.to_retries - - req->rq_timeout.to_retries; - if (task->tk_timeout > req->rq_timeout.to_maxval) - task->tk_timeout = req->rq_timeout.to_maxval; + task->tk_timeout <<= rpc_ntimeo(clnt->cl_rtt, timer) + req->rq_retries; + if (task->tk_timeout > xprt->timeout.to_maxval || task->tk_timeout == 0) + task->tk_timeout = xprt->timeout.to_maxval; } else - task->tk_timeout = req->rq_timeout.to_current; + task->tk_timeout = req->rq_timeout; /* Don't race with disconnect */ if (!xprt_connected(xprt)) task->tk_status = -ENOTCONN; @@ -1324,7 +1353,7 @@ xprt_request_init(struct rpc_task *task, { struct rpc_rqst *req = task->tk_rqstp; - req->rq_timeout = xprt->timeout; + req->rq_timeout = xprt->timeout.to_initval; req->rq_task = task; req->rq_xprt = xprt; req->rq_xid = xprt_alloc_xid(xprt); @@ -1381,7 +1410,6 @@ xprt_default_timeout(struct rpc_timeout void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr) { - to->to_current = to->to_initval = to->to_increment = incr; to->to_maxval = incr * retr; @@ -1446,7 +1474,6 @@ xprt_setup(int proto, struct sockaddr_in /* Set timeout parameters */ if (to) { xprt->timeout = *to; - xprt->timeout.to_current = to->to_initval; } else xprt_default_timeout(&xprt->timeout, xprt->prot);