fs/nfs/direct.c | 39 +- fs/nfs/file.c | 10 fs/nfs/inode.c | 110 ++++-- fs/nfs/nfs3proc.c | 55 --- fs/nfs/nfs4proc.c | 179 +++-------- fs/nfs/nfs4state.c | 2 fs/nfs/nfs4xdr.c | 43 +- fs/nfs/pagelist.c | 47 +- fs/nfs/proc.c | 46 -- fs/nfs/read.c | 63 ++- fs/nfs/unlink.c | 3 fs/nfs/write.c | 92 ++--- include/linux/nfs_fs.h | 37 +- include/linux/nfs_page.h | 29 - include/linux/nfs_xdr.h | 22 - include/linux/sunrpc/sched.h | 55 ++- include/linux/sunrpc/xprt.h | 10 net/sunrpc/auth_gss/auth_gss.c | 54 ++- net/sunrpc/auth_gss/gss_krb5_crypto.c | 18 - net/sunrpc/auth_gss/gss_krb5_mech.c | 8 net/sunrpc/auth_gss/gss_krb5_seal.c | 6 net/sunrpc/auth_gss/gss_krb5_seqnum.c | 2 net/sunrpc/auth_gss/gss_mech_switch.c | 14 net/sunrpc/auth_gss/gss_pseudoflavors.c | 21 - net/sunrpc/auth_gss/svcauth_gss.c | 10 net/sunrpc/clnt.c | 8 net/sunrpc/sched.c | 510 +++++++++----------------------- net/sunrpc/timer.c | 1 net/sunrpc/xprt.c | 83 +++-- 29 files changed, 679 insertions(+), 898 deletions(-) diff -u --recursive --new-file --show-c-function linux-2.6.6-rc2/fs/nfs/direct.c linux-2.6.6-10-file_ctx2/fs/nfs/direct.c --- linux-2.6.6-rc2/fs/nfs/direct.c 2004-04-21 15:27:50.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/direct.c 2004-04-21 15:29:59.000000000 -0400 @@ -109,7 +109,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 +117,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 +126,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 +151,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 +183,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 +193,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 +216,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 +239,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 +247,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 +259,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,7 +295,7 @@ 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) { @@ -330,7 +332,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, @@ -351,7 +353,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 +362,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 +385,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); @@ -422,6 +423,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; @@ -435,19 +437,20 @@ nfs_direct_IO(int rw, struct kiocb *iocb if (result < 0) goto out; + 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: diff -u --recursive --new-file --show-c-function linux-2.6.6-rc2/fs/nfs/file.c linux-2.6.6-10-file_ctx2/fs/nfs/file.c --- linux-2.6.6-rc2/fs/nfs/file.c 2004-04-21 15:27:47.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/file.c 2004-04-21 15:29:54.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); } @@ -206,6 +207,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 +216,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; diff -u --recursive --new-file --show-c-function linux-2.6.6-rc2/fs/nfs/inode.c linux-2.6.6-10-file_ctx2/fs/nfs/inode.c --- linux-2.6.6-rc2/fs/nfs/inode.c 2004-04-21 15:27:49.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/inode.c 2004-04-21 15:29:54.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-rc2/fs/nfs/nfs3proc.c linux-2.6.6-10-file_ctx2/fs/nfs/nfs3proc.c --- linux-2.6.6-rc2/fs/nfs/nfs3proc.c 2004-04-21 15:27:31.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/nfs3proc.c 2004-04-21 15:29:54.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); @@ -374,6 +359,11 @@ exit: }; dprintk("NFS call setattr (post-create)\n"); + if (!(sattr->ia_valid & ATTR_ATIME_SET)) + sattr->ia_valid |= ATTR_ATIME; + if (!(sattr->ia_valid & ATTR_MTIME_SET)) + sattr->ia_valid |= ATTR_MTIME; + /* Note: we could use a guarded setattr here, but I'm * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ @@ -827,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) { @@ -887,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-rc2/fs/nfs/nfs4proc.c linux-2.6.6-10-file_ctx2/fs/nfs/nfs4proc.c --- linux-2.6.6-rc2/fs/nfs/nfs4proc.c 2004-04-21 15:27:48.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/nfs4proc.c 2004-04-21 15:29:54.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-rc2/fs/nfs/nfs4state.c linux-2.6.6-10-file_ctx2/fs/nfs/nfs4state.c --- linux-2.6.6-rc2/fs/nfs/nfs4state.c 2004-04-21 15:27:17.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/nfs4state.c 2004-04-21 15:29:17.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-rc2/fs/nfs/nfs4xdr.c linux-2.6.6-10-file_ctx2/fs/nfs/nfs4xdr.c --- linux-2.6.6-rc2/fs/nfs/nfs4xdr.c 2004-04-21 15:27:58.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/nfs4xdr.c 2004-04-21 15:29:59.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); @@ -1030,26 +1039,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 +1075,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); diff -u --recursive --new-file --show-c-function linux-2.6.6-rc2/fs/nfs/pagelist.c linux-2.6.6-10-file_ctx2/fs/nfs/pagelist.c --- linux-2.6.6-rc2/fs/nfs/pagelist.c 2004-04-21 15:27:50.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/pagelist.c 2004-04-21 15:29:54.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-rc2/fs/nfs/proc.c linux-2.6.6-10-file_ctx2/fs/nfs/proc.c --- linux-2.6.6-rc2/fs/nfs/proc.c 2004-04-21 15:27:51.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/proc.c 2004-04-21 15:29:54.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-rc2/fs/nfs/read.c linux-2.6.6-10-file_ctx2/fs/nfs/read.c --- linux-2.6.6-rc2/fs/nfs/read.c 2004-04-21 15:27:16.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/read.c 2004-04-21 15:29:59.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-rc2/fs/nfs/unlink.c linux-2.6.6-10-file_ctx2/fs/nfs/unlink.c --- linux-2.6.6-rc2/fs/nfs/unlink.c 2004-04-21 15:27:51.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/unlink.c 2004-04-21 15:29:42.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-rc2/fs/nfs/write.c linux-2.6.6-10-file_ctx2/fs/nfs/write.c --- linux-2.6.6-rc2/fs/nfs/write.c 2004-04-21 15:27:48.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/fs/nfs/write.c 2004-04-21 15:29:59.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,18 +311,20 @@ 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 == offset) err = 0; } + put_nfs_open_context(ctx); unlock_kernel(); out: if (err != WRITEPAGE_ACTIVATE) @@ -398,7 +403,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--; @@ -444,7 +449,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); @@ -461,7 +466,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; } @@ -472,7 +477,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); @@ -613,9 +618,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; @@ -662,13 +667,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. @@ -678,7 +679,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) { @@ -699,9 +700,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; @@ -715,7 +716,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); } @@ -731,6 +732,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; @@ -741,7 +743,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); @@ -778,7 +780,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; @@ -854,16 +856,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; @@ -1023,7 +1024,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; } @@ -1048,16 +1049,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) @@ -1098,16 +1098,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); @@ -1226,7 +1225,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. @@ -1240,7 +1239,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; @@ -1307,13 +1306,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-rc2/include/linux/nfs_fs.h linux-2.6.6-10-file_ctx2/include/linux/nfs_fs.h --- linux-2.6.6-rc2/include/linux/nfs_fs.h 2004-04-21 15:27:22.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/include/linux/nfs_fs.h 2004-04-21 15:29:54.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; } /* diff -u --recursive --new-file --show-c-function linux-2.6.6-rc2/include/linux/nfs_page.h linux-2.6.6-10-file_ctx2/include/linux/nfs_page.h --- linux-2.6.6-rc2/include/linux/nfs_page.h 2004-04-21 15:27:18.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/include/linux/nfs_page.h 2004-04-21 15:29:54.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-rc2/include/linux/nfs_xdr.h linux-2.6.6-10-file_ctx2/include/linux/nfs_xdr.h --- linux-2.6.6-rc2/include/linux/nfs_xdr.h 2004-04-21 15:27:49.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/include/linux/nfs_xdr.h 2004-04-21 15:29:59.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-rc2/include/linux/sunrpc/sched.h linux-2.6.6-10-file_ctx2/include/linux/sunrpc/sched.h --- linux-2.6.6-rc2/include/linux/sunrpc/sched.h 2004-04-21 15:27:47.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/include/linux/sunrpc/sched.h 2004-04-21 15:29:48.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-rc2/include/linux/sunrpc/xprt.h linux-2.6.6-10-file_ctx2/include/linux/sunrpc/xprt.h --- linux-2.6.6-rc2/include/linux/sunrpc/xprt.h 2004-04-21 15:27:48.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/include/linux/sunrpc/xprt.h 2004-04-21 15:29:23.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-rc2/net/sunrpc/auth_gss/auth_gss.c linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/auth_gss.c --- linux-2.6.6-rc2/net/sunrpc/auth_gss/auth_gss.c 2004-04-21 15:27:25.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/auth_gss.c 2004-04-21 15:29:32.000000000 -0400 @@ -280,7 +280,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 +311,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 +352,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 +362,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 +395,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 +485,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 +529,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,7 +555,8 @@ 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); @@ -582,7 +594,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 +610,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 +629,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 +641,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 +661,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 +691,15 @@ 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); 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 +748,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 +769,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) @@ -789,9 +799,12 @@ 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; } @@ -814,7 +827,7 @@ gss_wrap_req(struct rpc_task *task, u32 offset, *q; struct iovec *iov; - dprintk("RPC: gss_wrap_body\n"); + dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid); BUG_ON(!ctx); if (ctx->gc_proc != RPC_GSS_PROC_DATA) { /* The spec seems a little ambiguous here, but I think that not @@ -869,7 +882,7 @@ gss_wrap_req(struct rpc_task *task, 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; } @@ -930,7 +943,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; } diff -u --recursive --new-file --show-c-function linux-2.6.6-rc2/net/sunrpc/auth_gss/gss_krb5_crypto.c linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_krb5_crypto.c --- linux-2.6.6-rc2/net/sunrpc/auth_gss/gss_krb5_crypto.c 2004-04-21 15:27:17.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_krb5_crypto.c 2004-04-21 15:29:32.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,10 +81,10 @@ 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); } @@ -100,14 +100,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,10 +121,10 @@ 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); } @@ -153,7 +153,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; } diff -u --recursive --new-file --show-c-function linux-2.6.6-rc2/net/sunrpc/auth_gss/gss_krb5_mech.c linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_krb5_mech.c --- linux-2.6.6-rc2/net/sunrpc/auth_gss/gss_krb5_mech.c 2004-04-21 15:27:47.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_krb5_mech.c 2004-04-21 15:29:32.000000000 -0400 @@ -100,7 +100,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 +155,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 +197,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,7 +211,7 @@ 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; } diff -u --recursive --new-file --show-c-function linux-2.6.6-rc2/net/sunrpc/auth_gss/gss_krb5_seal.c linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_krb5_seal.c --- linux-2.6.6-rc2/net/sunrpc/auth_gss/gss_krb5_seal.c 2004-04-21 15:27:16.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_krb5_seal.c 2004-04-21 15:29:32.000000000 -0400 @@ -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; } @@ -151,7 +151,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-rc2/net/sunrpc/auth_gss/gss_krb5_seqnum.c linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_krb5_seqnum.c --- linux-2.6.6-rc2/net/sunrpc/auth_gss/gss_krb5_seqnum.c 2004-04-21 15:27:21.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_krb5_seqnum.c 2004-04-21 15:29:32.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-rc2/net/sunrpc/auth_gss/gss_mech_switch.c linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_mech_switch.c --- linux-2.6.6-rc2/net/sunrpc/auth_gss/gss_mech_switch.c 2004-04-21 15:27:46.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_mech_switch.c 2004-04-21 15:29:32.000000000 -0400 @@ -81,7 +81,7 @@ gss_mech_register(struct xdr_netobj * me 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"); + dprintk("RPC: gss_mech_register: registered mechanism with oid:\n"); print_hexl((u32 *)mech_type->data, mech_type->len, 0); return 0; } @@ -93,11 +93,10 @@ do_gss_mech_unregister(struct gss_api_me list_del(&gm->gm_list); - dprintk("RPC: unregistered mechanism with oid:\n"); + 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"); + dprintk("RPC: We just unregistered a gss_mechanism which someone is still using.\n"); return -1; } else { return 0; @@ -145,7 +144,7 @@ gss_mech_get_by_OID(struct xdr_netobj *m { struct gss_api_mech *pos, *gm = NULL; - dprintk("RPC: gss_mech_get_by_OID searching for mechanism with OID:\n"); + 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) { @@ -157,7 +156,7 @@ gss_mech_get_by_OID(struct xdr_netobj *m } } spin_unlock(®istered_mechs_lock); - dprintk("RPC: gss_mech_get_by_OID %s it\n", gm ? "found" : "didn't find"); + dprintk("RPC: gss_mech_get_by_OID %s it\n", gm ? "found" : "didn't find"); return gm; } @@ -244,7 +243,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-rc2/net/sunrpc/auth_gss/gss_pseudoflavors.c linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_pseudoflavors.c --- linux-2.6.6-rc2/net/sunrpc/auth_gss/gss_pseudoflavors.c 2004-04-21 15:27:33.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/gss_pseudoflavors.c 2004-04-21 15:29:32.000000000 -0400 @@ -82,12 +82,13 @@ gss_register_triple(u32 pseudoflavor, st spin_lock(®istered_triples_lock); if (do_lookup_triple_by_pseudoflavor(pseudoflavor)) { - printk("Registered pseudoflavor %d again\n", pseudoflavor); + printk(KERN_WARNING "RPC: 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); + dprintk("RPC: registered pseudoflavor %d\n", pseudoflavor); return 0; @@ -145,7 +146,7 @@ gss_cmp_triples(u32 oid_len, char *oid_d oid.len = oid_len; oid.data = oid_data; - dprintk("RPC: gss_cmp_triples \n"); + dprintk("RPC: gss_cmp_triples\n"); print_sec_triple(&oid,qop,service); spin_lock(®istered_triples_lock); @@ -158,7 +159,7 @@ gss_cmp_triples(u32 oid_len, char *oid_d } } spin_unlock(®istered_triples_lock); - dprintk("RPC: gss_cmp_triples return %d\n", pseudoflavor); + dprintk("RPC: gss_cmp_triples return %d\n", pseudoflavor); return pseudoflavor; } @@ -193,8 +194,8 @@ gss_pseudoflavor_to_service(u32 pseudofl 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); + dprintk("RPC: gss_pseudoflavor_to_service called with unsupported pseudoflavor %d\n", + pseudoflavor); return 0; } return triple->service; @@ -211,8 +212,8 @@ gss_pseudoflavor_to_mech(u32 pseudoflavo if (triple) mech = gss_mech_get(triple->mech); else - dprintk("RPC: gss_pseudoflavor_to_mech called with" - " unsupported pseudoflavor %d\n", pseudoflavor); + dprintk("RPC: gss_pseudoflavor_to_mech called with unsupported pseudoflavor %d\n", + pseudoflavor); return mech; } @@ -223,8 +224,8 @@ gss_pseudoflavor_to_mechOID(u32 pseudofl mech = gss_pseudoflavor_to_mech(pseudoflavor); if (!mech) { - dprintk("RPC: gss_pseudoflavor_to_mechOID called with" - " unsupported pseudoflavor %d\n", pseudoflavor); + dprintk("RPC: gss_pseudoflavor_to_mechOID called with unsupported pseudoflavor %d\n", + pseudoflavor); return -1; } oid->len = mech->gm_oid.len; diff -u --recursive --new-file --show-c-function linux-2.6.6-rc2/net/sunrpc/auth_gss/svcauth_gss.c linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/svcauth_gss.c --- linux-2.6.6-rc2/net/sunrpc/auth_gss/svcauth_gss.c 2004-04-21 15:27:25.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/auth_gss/svcauth_gss.c 2004-04-21 15:29:32.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; @@ -755,7 +755,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-rc2/net/sunrpc/clnt.c linux-2.6.6-10-file_ctx2/net/sunrpc/clnt.c --- linux-2.6.6-rc2/net/sunrpc/clnt.c 2004-04-21 15:27:23.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/clnt.c 2004-04-21 15:29:42.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-rc2/net/sunrpc/sched.c linux-2.6.6-10-file_ctx2/net/sunrpc/sched.c --- linux-2.6.6-rc2/net/sunrpc/sched.c 2004-04-21 15:27:34.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/sched.c 2004-04-21 15:29:48.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-rc2/net/sunrpc/timer.c linux-2.6.6-10-file_ctx2/net/sunrpc/timer.c --- linux-2.6.6-rc2/net/sunrpc/timer.c 2004-04-21 15:27:50.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/timer.c 2004-04-21 15:29:23.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-rc2/net/sunrpc/xprt.c linux-2.6.6-10-file_ctx2/net/sunrpc/xprt.c --- linux-2.6.6-rc2/net/sunrpc/xprt.c 2004-04-21 15:27:47.000000000 -0400 +++ linux-2.6.6-10-file_ctx2/net/sunrpc/xprt.c 2004-04-21 15:29:42.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; } /* @@ -1069,7 +1091,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 +1188,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 +1244,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 +1271,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 +1345,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 +1402,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 +1466,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);