From 070ea60214c1894c9eec86ca9aa5dff57a5ab525 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sat, 19 May 2007 17:22:52 -0400 Subject: NFS: Clean ups in fs/nfs/direct.c Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/direct.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 00eee87510f..4c97e55e86e 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -763,10 +763,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, (unsigned long) count, (long long) pos); if (nr_segs != 1) - return -EINVAL; - - if (count < 0) goto out; + retval = -EFAULT; if (!access_ok(VERIFY_WRITE, buf, count)) goto out; @@ -814,7 +812,7 @@ out: ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { - ssize_t retval; + ssize_t retval = -EINVAL; struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; /* XXX: temporary */ @@ -827,7 +825,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, (unsigned long) count, (long long) pos); if (nr_segs != 1) - return -EINVAL; + goto out; retval = generic_write_checks(file, &pos, &count, 0); if (retval) -- cgit v1.2.3-70-g09d2 From d9df8d6b38228afab519094048aa2c082b0b2cf4 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 22 May 2007 10:22:20 -0400 Subject: NFS: Don't fail an O_DIRECT read/write if get_user_pages() returns pages There is no need to fail the entire O_DIRECT read/write just because get_user_pages() returned fewer pages than we requested. Signed-off-by: Trond Myklebust --- fs/nfs/direct.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 4c97e55e86e..f1b153ad645 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -295,9 +295,14 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo break; } if ((unsigned)result < data->npages) { - nfs_direct_release_pages(data->pagevec, result); - nfs_readdata_release(data); - break; + bytes = result * PAGE_SIZE; + if (bytes <= pgbase) { + nfs_direct_release_pages(data->pagevec, result); + nfs_readdata_release(data); + break; + } + bytes -= pgbase; + data->npages = result; } get_dreq(dreq); @@ -630,9 +635,14 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l break; } if ((unsigned)result < data->npages) { - nfs_direct_release_pages(data->pagevec, result); - nfs_writedata_release(data); - break; + bytes = result * PAGE_SIZE; + if (bytes <= pgbase) { + nfs_direct_release_pages(data->pagevec, result); + nfs_writedata_release(data); + break; + } + bytes -= pgbase; + data->npages = result; } get_dreq(dreq); -- cgit v1.2.3-70-g09d2 From 44dd151d5c21234cc534c47d7382f5c28c3143cd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 19 May 2007 11:58:03 -0400 Subject: NFS: Don't mark a written page as uptodate until it is on disk The write may fail, so we should not mark the page as uptodate until we are certain that the data has been accepted and written to disk by the server. Signed-off-by: Trond Myklebust --- fs/nfs/write.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/write.c b/fs/nfs/write.c index af344a158e0..b853959d964 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -191,8 +191,6 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, } /* Update file length */ nfs_grow_file(page, offset, count); - /* Set the PG_uptodate flag? */ - nfs_mark_uptodate(page, offset, count); nfs_unlock_request(req); return 0; } @@ -751,7 +749,12 @@ int nfs_updatepage(struct file *file, struct page *page, static void nfs_writepage_release(struct nfs_page *req) { - if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { + if (PageError(req->wb_page)) { + nfs_end_page_writeback(req->wb_page); + nfs_inode_remove_request(req); + } else if (!nfs_reschedule_unstable_write(req)) { + /* Set the PG_uptodate flag */ + nfs_mark_uptodate(req->wb_page, req->wb_pgbase, req->wb_bytes); nfs_end_page_writeback(req->wb_page); nfs_inode_remove_request(req); } else @@ -1039,6 +1042,8 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) dprintk(" marked for commit\n"); goto next; } + /* Set the PG_uptodate flag? */ + nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); dprintk(" OK\n"); remove_request: nfs_end_page_writeback(page); @@ -1249,6 +1254,9 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) * returned by the server against all stored verfs. */ if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) { /* We have a match */ + /* Set the PG_uptodate flag */ + nfs_mark_uptodate(req->wb_page, req->wb_pgbase, + req->wb_bytes); nfs_inode_remove_request(req); dprintk(" OK\n"); goto next; -- cgit v1.2.3-70-g09d2 From de05a0cc2a2ae16eb8d8dbf88fe728ace45beb9a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 20 May 2007 13:05:05 -0400 Subject: NFS: Minor read optimisation... Since PG_uptodate may now end up getting set during the call to nfs_wb_page(), we can avoid putting a read request on the wire in those situations. Signed-off-by: Trond Myklebust --- fs/nfs/read.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 7bd7cb95c03..c07d0d10d9e 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -483,17 +483,19 @@ int nfs_readpage(struct file *file, struct page *page) */ error = nfs_wb_page(inode, page); if (error) - goto out_error; + goto out_unlock; + if (PageUptodate(page)) + goto out_unlock; error = -ESTALE; if (NFS_STALE(inode)) - goto out_error; + goto out_unlock; if (file == NULL) { error = -EBADF; ctx = nfs_find_open_context(inode, NULL, FMODE_READ); if (ctx == NULL) - goto out_error; + goto out_unlock; } else ctx = get_nfs_open_context((struct nfs_open_context *) file->private_data); @@ -502,8 +504,7 @@ int nfs_readpage(struct file *file, struct page *page) put_nfs_open_context(ctx); return error; - -out_error: +out_unlock: unlock_page(page); return error; } @@ -520,21 +521,32 @@ readpage_async_filler(void *data, struct page *page) struct inode *inode = page->mapping->host; struct nfs_page *new; unsigned int len; + int error; + + error = nfs_wb_page(inode, page); + if (error) + goto out_unlock; + if (PageUptodate(page)) + goto out_unlock; - nfs_wb_page(inode, page); len = nfs_page_length(page); if (len == 0) return nfs_return_empty_page(page); + new = nfs_create_request(desc->ctx, inode, page, 0, len); - if (IS_ERR(new)) { - SetPageError(page); - unlock_page(page); - return PTR_ERR(new); - } + if (IS_ERR(new)) + goto out_error; + if (len < PAGE_CACHE_SIZE) zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0); nfs_pageio_add_request(desc->pgio, new); return 0; +out_error: + error = PTR_ERR(new); + SetPageError(page); +out_unlock: + unlock_page(page); + return error; } int nfs_readpages(struct file *filp, struct address_space *mapping, -- cgit v1.2.3-70-g09d2 From 88be9f990fe70f0f177ef44a16a477599e91f825 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Jun 2007 10:42:27 -0400 Subject: NFS: Replace vfsmount and dentry in nfs_open_context with struct path Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 2 +- fs/nfs/direct.c | 4 ++-- fs/nfs/inode.c | 10 +++++----- fs/nfs/nfs4proc.c | 6 +++--- fs/nfs/pagelist.c | 6 +++--- fs/nfs/read.c | 6 +++--- fs/nfs/write.c | 20 ++++++++++---------- include/linux/nfs_fs.h | 4 ++-- 8 files changed, 29 insertions(+), 29 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 7f37d1bea83..b47c156a711 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -74,7 +74,7 @@ again: continue; get_nfs_open_context(ctx); spin_unlock(&inode->i_lock); - err = nfs4_open_delegation_recall(ctx->dentry, state); + err = nfs4_open_delegation_recall(ctx->path.dentry, state); if (err >= 0) err = nfs_delegation_claim_locks(ctx, state); put_nfs_open_context(ctx); diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index f1b153ad645..a5c82b6f3b4 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -266,7 +266,7 @@ static const struct rpc_call_ops nfs_read_direct_ops = { static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos) { struct nfs_open_context *ctx = dreq->ctx; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; size_t rsize = NFS_SERVER(inode)->rsize; unsigned int pgbase; int result; @@ -606,7 +606,7 @@ static const struct rpc_call_ops nfs_write_direct_ops = { static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync) { struct nfs_open_context *ctx = dreq->ctx; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; size_t wsize = NFS_SERVER(inode)->wsize; unsigned int pgbase; int result; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bd9f5a83659..cc7a9064be9 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -462,8 +462,8 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (ctx != NULL) { atomic_set(&ctx->count, 1); - ctx->dentry = dget(dentry); - ctx->vfsmnt = mntget(mnt); + ctx->path.dentry = dget(dentry); + ctx->path.mnt = mntget(mnt); ctx->cred = get_rpccred(cred); ctx->state = NULL; ctx->lockowner = current->files; @@ -484,7 +484,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) { if (atomic_dec_and_test(&ctx->count)) { if (!list_empty(&ctx->list)) { - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = ctx->path.dentry->d_inode; spin_lock(&inode->i_lock); list_del(&ctx->list); spin_unlock(&inode->i_lock); @@ -493,8 +493,8 @@ void put_nfs_open_context(struct nfs_open_context *ctx) nfs4_close_state(ctx->state, ctx->mode); if (ctx->cred != NULL) put_rpccred(ctx->cred); - dput(ctx->dentry); - mntput(ctx->vfsmnt); + dput(ctx->path.dentry); + mntput(ctx->path.mnt); kfree(ctx); } } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 648e0ac0f90..4d641cbdbde 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -512,7 +512,7 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta ctx = nfs4_state_find_open_context(state); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = nfs4_do_open_reclaim(sp, state, ctx->dentry); + ret = nfs4_do_open_reclaim(sp, state, ctx->path.dentry); put_nfs_open_context(ctx); return ret; } @@ -862,7 +862,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta ctx = nfs4_state_find_open_context(state); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = nfs4_do_open_expired(sp, state, ctx->dentry); + ret = nfs4_do_open_expired(sp, state, ctx->path.dentry); put_nfs_open_context(ctx); return ret; } @@ -3285,7 +3285,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, sizeof(data->lsp->ls_stateid.data)); data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; - renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); + renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); } nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); out: diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index c5bb51a29e8..f8a4ba53393 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -114,7 +114,7 @@ void nfs_unlock_request(struct nfs_page *req) */ int nfs_set_page_writeback_locked(struct nfs_page *req) { - struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); + struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); if (!nfs_lock_request(req)) return 0; @@ -127,7 +127,7 @@ int nfs_set_page_writeback_locked(struct nfs_page *req) */ void nfs_clear_page_writeback(struct nfs_page *req) { - struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); + struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); if (req->wb_page != NULL) { spin_lock(&nfsi->req_lock); @@ -193,7 +193,7 @@ static int nfs_wait_bit_interruptible(void *word) int nfs_wait_on_request(struct nfs_page *req) { - struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode); + struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->path.dentry->d_inode); sigset_t oldmask; int ret = 0; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index c07d0d10d9e..6ae2e58ed05 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -145,8 +145,8 @@ static void nfs_readpage_release(struct nfs_page *req) unlock_page(req->wb_page); dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", - req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); nfs_clear_request(req); @@ -164,7 +164,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, int flags; data->req = req; - data->inode = inode = req->wb_context->dentry->d_inode; + data->inode = inode = req->wb_context->path.dentry->d_inode; data->cred = req->wb_context->cred; data->args.fh = NFS_FH(inode); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index b853959d964..9e7c21da864 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -407,7 +407,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) */ static void nfs_inode_remove_request(struct nfs_page *req) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); BUG_ON (!NFS_WBACK_BUSY(req)); @@ -455,7 +455,7 @@ nfs_dirty_request(struct nfs_page *req) static void nfs_mark_request_commit(struct nfs_page *req) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&nfsi->req_lock); @@ -789,7 +789,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, * NB: take care not to mess about with data->commit et al. */ data->req = req; - data->inode = inode = req->wb_context->dentry->d_inode; + data->inode = inode = req->wb_context->path.dentry->d_inode; data->cred = req->wb_context->cred; data->args.fh = NFS_FH(inode); @@ -957,8 +957,8 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) struct page *page = req->wb_page; dprintk("NFS: write (%s/%Ld %d@%Ld)", - req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); @@ -1023,8 +1023,8 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) page = req->wb_page; dprintk("NFS: write (%s/%Ld %d@%Ld)", - req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); @@ -1162,7 +1162,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, list_splice_init(head, &data->pages); first = nfs_list_entry(data->pages.next); - inode = first->wb_context->dentry->d_inode; + inode = first->wb_context->path.dentry->d_inode; data->inode = inode; data->cred = first->wb_context->cred; @@ -1239,8 +1239,8 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); dprintk("NFS: commit (%s/%Ld %d@%Ld)", - req->wb_context->dentry->d_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), + req->wb_context->path.dentry->d_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); if (task->tk_status < 0) { diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 0543439a97a..07eea8f64ec 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -70,8 +71,7 @@ struct nfs_access_entry { struct nfs4_state; struct nfs_open_context { atomic_t count; - struct vfsmount *vfsmnt; - struct dentry *dentry; + struct path path; struct rpc_cred *cred; struct nfs4_state *state; fl_owner_t lockowner; -- cgit v1.2.3-70-g09d2 From 539cd03a5708c9861a3e738e6f363ad743c85ddf Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Jun 2007 11:46:42 -0400 Subject: NFSv4: Cleanup: pass the nfs_open_context to open recovery code Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 2 +- fs/nfs/delegation.h | 2 +- fs/nfs/nfs4proc.c | 38 +++++++++++++++++++------------------- 3 files changed, 21 insertions(+), 21 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index b47c156a711..9f17b91205c 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -74,7 +74,7 @@ again: continue; get_nfs_open_context(ctx); spin_unlock(&inode->i_lock); - err = nfs4_open_delegation_recall(ctx->path.dentry, state); + err = nfs4_open_delegation_recall(ctx, state); if (err >= 0) err = nfs_delegation_claim_locks(ctx, state); put_nfs_open_context(ctx); diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 2cfd4b24c7f..f6e42fb21af 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -39,7 +39,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp); /* NFSv4 delegation-related procedures */ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); -int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); +int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state); int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4d641cbdbde..c83db9def0f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -462,7 +462,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * * OPEN_RECLAIM: * reclaim state on the server after a reboot. */ -static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) +static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) { struct nfs_delegation *delegation = NFS_I(state->inode)->delegation; struct nfs4_opendata *opendata; @@ -478,7 +478,7 @@ static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state } delegation_type = delegation->type; } - opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); + opendata = nfs4_opendata_alloc(ctx->path.dentry, state->owner, 0, NULL); if (opendata == NULL) return -ENOMEM; opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; @@ -490,13 +490,13 @@ static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state return status; } -static int nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) +static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_exception exception = { }; int err; do { - err = _nfs4_do_open_reclaim(sp, state, dentry); + err = _nfs4_do_open_reclaim(ctx, state); if (err != -NFS4ERR_DELAY) break; nfs4_handle_exception(server, err, &exception); @@ -512,12 +512,12 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta ctx = nfs4_state_find_open_context(state); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = nfs4_do_open_reclaim(sp, state, ctx->path.dentry); + ret = nfs4_do_open_reclaim(ctx, state); put_nfs_open_context(ctx); return ret; } -static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) +static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state) { struct nfs4_state_owner *sp = state->owner; struct nfs4_opendata *opendata; @@ -525,7 +525,7 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) return 0; - opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); + opendata = nfs4_opendata_alloc(ctx->path.dentry, sp, 0, NULL); if (opendata == NULL) return -ENOMEM; opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; @@ -536,13 +536,13 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state return ret; } -int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) +int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state) { struct nfs4_exception exception = { }; - struct nfs_server *server = NFS_SERVER(dentry->d_inode); + struct nfs_server *server = NFS_SERVER(state->inode); int err; do { - err = _nfs4_open_delegation_recall(dentry, state); + err = _nfs4_open_delegation_recall(ctx, state); switch (err) { case 0: return err; @@ -811,7 +811,7 @@ static int nfs4_recover_expired_lease(struct nfs_server *server) * reclaim state on the server after a network partition. * Assumes caller holds the appropriate lock */ -static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) +static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) { struct inode *inode = state->inode; struct nfs_delegation *delegation = NFS_I(inode)->delegation; @@ -820,34 +820,34 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st int ret; if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { - ret = _nfs4_do_access(inode, sp->so_cred, openflags); + ret = _nfs4_do_access(inode, ctx->cred, openflags); if (ret < 0) return ret; memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); set_bit(NFS_DELEGATED_STATE, &state->flags); return 0; } - opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL); + opendata = nfs4_opendata_alloc(ctx->path.dentry, state->owner, openflags, NULL); if (opendata == NULL) return -ENOMEM; ret = nfs4_open_recover(opendata, state); if (ret == -ESTALE) { /* Invalidate the state owner so we don't ever use it again */ - nfs4_drop_state_owner(sp); - d_drop(dentry); + nfs4_drop_state_owner(state->owner); + d_drop(ctx->path.dentry); } nfs4_opendata_free(opendata); return ret; } -static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) +static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) { - struct nfs_server *server = NFS_SERVER(dentry->d_inode); + struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_exception exception = { }; int err; do { - err = _nfs4_open_expired(sp, state, dentry); + err = _nfs4_open_expired(ctx, state); if (err == -NFS4ERR_DELAY) nfs4_handle_exception(server, err, &exception); } while (exception.retry); @@ -862,7 +862,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta ctx = nfs4_state_find_open_context(state); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = nfs4_do_open_expired(sp, state, ctx->path.dentry); + ret = nfs4_do_open_expired(ctx, state); put_nfs_open_context(ctx); return ret; } -- cgit v1.2.3-70-g09d2 From ad389da79f7bf9dc12dbc79c9c2740f9ed2f13d1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Jun 2007 12:30:00 -0400 Subject: NFSv4: Ensure asynchronous open() calls always pin the mountpoint A number of race conditions may currently ensue if the user presses ^C and then unmounts the partition while an asynchronous open() is in progress. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 2 +- fs/nfs/nfs4proc.c | 48 +++++++++++++++++++++++++++++++----------------- 2 files changed, 32 insertions(+), 18 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c27258b5d3e..4948ec1dd9b 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1244,7 +1244,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; - if (nd && (nd->flags & LOOKUP_CREATE)) + if ((nd->flags & LOOKUP_CREATE) != 0) open_flags = nd->intent.open.flags; lock_kernel(); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c83db9def0f..895e8e649c9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -221,7 +221,7 @@ struct nfs4_opendata { struct nfs_open_confirmres c_res; struct nfs_fattr f_attr; struct nfs_fattr dir_attr; - struct dentry *dentry; + struct path path; struct dentry *dir; struct nfs4_state_owner *owner; struct iattr attrs; @@ -230,11 +230,11 @@ struct nfs4_opendata { int cancelled; }; -static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, +static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, struct nfs4_state_owner *sp, int flags, const struct iattr *attrs) { - struct dentry *parent = dget_parent(dentry); + struct dentry *parent = dget_parent(path->dentry); struct inode *dir = parent->d_inode; struct nfs_server *server = NFS_SERVER(dir); struct nfs4_opendata *p; @@ -246,7 +246,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, if (p->o_arg.seqid == NULL) goto err_free; atomic_set(&p->count, 1); - p->dentry = dget(dentry); + p->path.mnt = mntget(path->mnt); + p->path.dentry = dget(path->dentry); p->dir = parent; p->owner = sp; atomic_inc(&sp->so_count); @@ -254,7 +255,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, p->o_arg.open_flags = flags, p->o_arg.clientid = server->nfs_client->cl_clientid; p->o_arg.id = sp->so_id; - p->o_arg.name = &dentry->d_name; + p->o_arg.name = &p->path.dentry->d_name; p->o_arg.server = server; p->o_arg.bitmask = server->attr_bitmask; p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; @@ -288,7 +289,8 @@ static void nfs4_opendata_free(struct nfs4_opendata *p) nfs_free_seqid(p->o_arg.seqid); nfs4_put_state_owner(p->owner); dput(p->dir); - dput(p->dentry); + dput(p->path.dentry); + mntput(p->path.mnt); kfree(p); } } @@ -478,7 +480,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state } delegation_type = delegation->type; } - opendata = nfs4_opendata_alloc(ctx->path.dentry, state->owner, 0, NULL); + opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); if (opendata == NULL) return -ENOMEM; opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; @@ -525,7 +527,7 @@ static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) return 0; - opendata = nfs4_opendata_alloc(ctx->path.dentry, sp, 0, NULL); + opendata = nfs4_opendata_alloc(&ctx->path, sp, 0, NULL); if (opendata == NULL) return -ENOMEM; opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; @@ -827,7 +829,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s set_bit(NFS_DELEGATED_STATE, &state->flags); return 0; } - opendata = nfs4_opendata_alloc(ctx->path.dentry, state->owner, openflags, NULL); + opendata = nfs4_opendata_alloc(&ctx->path, state->owner, openflags, NULL); if (opendata == NULL) return -ENOMEM; ret = nfs4_open_recover(opendata, state); @@ -955,7 +957,7 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st /* * Returns a referenced nfs4_state */ -static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) +static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) { struct nfs4_state_owner *sp; struct nfs4_state *state = NULL; @@ -975,7 +977,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st goto err_put_state_owner; down_read(&clp->cl_sem); status = -ENOMEM; - opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); + opendata = nfs4_opendata_alloc(path, sp, flags, sattr); if (opendata == NULL) goto err_release_rwsem; @@ -1006,14 +1008,14 @@ out_err: } -static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred) +static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred) { struct nfs4_exception exception = { }; struct nfs4_state *res; int status; do { - status = _nfs4_do_open(dir, dentry, flags, sattr, cred, &res); + status = _nfs4_do_open(dir, path, flags, sattr, cred, &res); if (status == 0) break; /* NOTE: BAD_SEQID means the server and client disagree about the @@ -1259,6 +1261,10 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, str struct dentry * nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { + struct path path = { + .mnt = nd->mnt, + .dentry = dentry, + }; struct iattr attr; struct rpc_cred *cred; struct nfs4_state *state; @@ -1277,7 +1283,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); if (IS_ERR(cred)) return (struct dentry *)cred; - state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); + state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); put_rpccred(cred); if (IS_ERR(state)) { if (PTR_ERR(state) == -ENOENT) @@ -1294,6 +1300,10 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) int nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) { + struct path path = { + .mnt = nd->mnt, + .dentry = dentry, + }; struct rpc_cred *cred; struct nfs4_state *state; @@ -1302,7 +1312,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st return PTR_ERR(cred); state = nfs4_open_delegated(dentry->d_inode, openflags, cred); if (IS_ERR(state)) - state = nfs4_do_open(dir, dentry, openflags, NULL, cred); + state = nfs4_do_open(dir, &path, openflags, NULL, cred); put_rpccred(cred); if (IS_ERR(state)) { switch (PTR_ERR(state)) { @@ -1752,6 +1762,10 @@ static int nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nameidata *nd) { + struct path path = { + .mnt = nd->mnt, + .dentry = dentry, + }; struct nfs4_state *state; struct rpc_cred *cred; int status = 0; @@ -1761,7 +1775,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, status = PTR_ERR(cred); goto out; } - state = nfs4_do_open(dir, dentry, flags, sattr, cred); + state = nfs4_do_open(dir, &path, flags, sattr, cred); put_rpccred(cred); if (IS_ERR(state)) { status = PTR_ERR(state); @@ -1774,7 +1788,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, if (status == 0) nfs_setattr_update_inode(state->inode, sattr); } - if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN)) + if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) status = nfs4_intent_set_file(nd, dentry, state); else nfs4_close_state(state, flags); -- cgit v1.2.3-70-g09d2 From 4a35bd41aff5714deb41c8f14766df3871e2e8f7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Jun 2007 10:31:33 -0400 Subject: NFSv4: Ensure that nfs4_do_close() doesn't race with umount nfs4_do_close() does not currently have any way to ensure that the user won't attempt to unmount the partition while the asynchronous RPC call is completing. This again may cause Oopses in nfs_update_inode(). Add a vfsmount argument to nfs4_close_state to ensure that the partition remains mounted while we're closing the file. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 19 +------------------ fs/nfs/nfs4_fs.h | 6 +++--- fs/nfs/nfs4proc.c | 35 ++++++++++++++++++++--------------- fs/nfs/nfs4state.c | 4 ++-- 4 files changed, 26 insertions(+), 38 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index cc7a9064be9..23ecf0334a1 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -490,7 +490,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) spin_unlock(&inode->i_lock); } if (ctx->state != NULL) - nfs4_close_state(ctx->state, ctx->mode); + nfs4_close_state(&ctx->path, ctx->state, ctx->mode); if (ctx->cred != NULL) put_rpccred(ctx->cred); dput(ctx->path.dentry); @@ -1103,27 +1103,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) */ void nfs4_clear_inode(struct inode *inode) { - struct nfs_inode *nfsi = NFS_I(inode); - /* If we are holding a delegation, return it! */ nfs_inode_return_delegation(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; - - state = list_entry(nfsi->open_states.next, - struct nfs4_state, - inode_states); - dprintk("%s(%s/%Ld): found unclaimed NFSv4 state %p\n", - __FUNCTION__, - inode->i_sb->s_id, - (long long)NFS_FILEID(inode), - state); - BUG_ON(atomic_read(&state->count) != 1); - nfs4_close_state(state, state->state); - } } #endif diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index cf3a17eb5c0..c97a0ad8430 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -165,7 +165,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); -extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); +extern int nfs4_do_close(struct path *path, struct nfs4_state *state); extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); @@ -196,7 +196,7 @@ extern void nfs4_put_state_owner(struct nfs4_state_owner *); extern void nfs4_drop_state_owner(struct nfs4_state_owner *); extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); extern void nfs4_put_open_state(struct nfs4_state *); -extern void nfs4_close_state(struct nfs4_state *, mode_t); +extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t); extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); extern void nfs4_schedule_state_recovery(struct nfs_client *); extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); @@ -222,7 +222,7 @@ extern struct svc_version nfs4_callback_version1; #else -#define nfs4_close_state(a, b) do { } while (0) +#define nfs4_close_state(a, b, c) do { } while (0) #endif /* CONFIG_NFS_V4 */ #endif /* __LINUX_FS_NFS_NFS4_FS.H */ diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 895e8e649c9..8feaf232f2e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -453,7 +453,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * opendata->owner->so_cred, &opendata->o_res); } - nfs4_close_state(newstate, opendata->o_arg.open_flags); + nfs4_close_state(&opendata->path, newstate, opendata->o_arg.open_flags); } if (newstate != state) return -ESTALE; @@ -603,7 +603,7 @@ static void nfs4_open_confirm_release(void *calldata) nfs_confirm_seqid(&data->owner->so_seqid, 0); state = nfs4_opendata_to_nfs4_state(data); if (state != NULL) - nfs4_close_state(state, data->o_arg.open_flags); + nfs4_close_state(&data->path, state, data->o_arg.open_flags); out_free: nfs4_opendata_free(data); } @@ -706,7 +706,7 @@ static void nfs4_open_release(void *calldata) nfs_confirm_seqid(&data->owner->so_seqid, 0); state = nfs4_opendata_to_nfs4_state(data); if (state != NULL) - nfs4_close_state(state, data->o_arg.open_flags); + nfs4_close_state(&data->path, state, data->o_arg.open_flags); out_free: nfs4_opendata_free(data); } @@ -1103,6 +1103,7 @@ static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, } struct nfs4_closedata { + struct path path; struct inode *inode; struct nfs4_state *state; struct nfs_closeargs arg; @@ -1119,6 +1120,8 @@ static void nfs4_free_closedata(void *data) nfs4_put_open_state(calldata->state); nfs_free_seqid(calldata->arg.seqid); nfs4_put_state_owner(sp); + dput(calldata->path.dentry); + mntput(calldata->path.mnt); kfree(calldata); } @@ -1211,18 +1214,18 @@ static const struct rpc_call_ops nfs4_close_ops = { * * NOTE: Caller must be holding the sp->so_owner semaphore! */ -int nfs4_do_close(struct inode *inode, struct nfs4_state *state) +int nfs4_do_close(struct path *path, struct nfs4_state *state) { - struct nfs_server *server = NFS_SERVER(inode); + struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_closedata *calldata; int status = -ENOMEM; calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); if (calldata == NULL) goto out; - calldata->inode = inode; + calldata->inode = state->inode; calldata->state = state; - calldata->arg.fh = NFS_FH(inode); + calldata->arg.fh = NFS_FH(state->inode); calldata->arg.stateid = &state->stateid; /* Serialization for the sequence id */ calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); @@ -1231,6 +1234,8 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state) calldata->arg.bitmask = server->attr_bitmask; calldata->res.fattr = &calldata->fattr; calldata->res.server = server; + calldata->path.mnt = mntget(path->mnt); + calldata->path.dentry = dget(path->dentry); status = nfs4_call_async(server->client, &nfs4_close_ops, calldata); if (status == 0) @@ -1243,18 +1248,18 @@ out: return status; } -static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state) +static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state) { struct file *filp; - filp = lookup_instantiate_filp(nd, dentry, NULL); + filp = lookup_instantiate_filp(nd, path->dentry, NULL); if (!IS_ERR(filp)) { struct nfs_open_context *ctx; ctx = (struct nfs_open_context *)filp->private_data; ctx->state = state; return 0; } - nfs4_close_state(state, nd->intent.open.flags); + nfs4_close_state(path, state, nd->intent.open.flags); return PTR_ERR(filp); } @@ -1293,7 +1298,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) res = d_add_unique(dentry, igrab(state->inode)); if (res != NULL) dentry = res; - nfs4_intent_set_file(nd, dentry, state); + nfs4_intent_set_file(nd, &path, state); return res; } @@ -1328,10 +1333,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st } } if (state->inode == dentry->d_inode) { - nfs4_intent_set_file(nd, dentry, state); + nfs4_intent_set_file(nd, &path, state); return 1; } - nfs4_close_state(state, openflags); + nfs4_close_state(&path, state, openflags); out_drop: d_drop(dentry); return 0; @@ -1789,9 +1794,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, nfs_setattr_update_inode(state->inode, sattr); } if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) - status = nfs4_intent_set_file(nd, dentry, state); + status = nfs4_intent_set_file(nd, &path, state); else - nfs4_close_state(state, flags); + nfs4_close_state(&path, state, flags); out: return status; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 8ed79d5c54f..a85138ef67a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -341,7 +341,7 @@ void nfs4_put_open_state(struct nfs4_state *state) /* * Close the current file. */ -void nfs4_close_state(struct nfs4_state *state, mode_t mode) +void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) { struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; @@ -375,7 +375,7 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) spin_unlock(&inode->i_lock); spin_unlock(&owner->so_lock); - if (oldstate != newstate && nfs4_do_close(inode, state) == 0) + if (oldstate != newstate && nfs4_do_close(path, state) == 0) return; nfs4_put_open_state(state); nfs4_put_state_owner(owner); -- cgit v1.2.3-70-g09d2 From b39e625b6e75aa70e26c13f9378756bb5f2af032 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 11 Jun 2007 23:05:07 -0400 Subject: NFSv4: Clean up nfs4_call_async() Use rpc_run_task() instead of doing it ourselves. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 26 +++++++++----------------- fs/nfs/nfs4state.c | 9 +++++---- net/sunrpc/sunrpc_syms.c | 1 - 3 files changed, 14 insertions(+), 22 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8feaf232f2e..3cc75445a68 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -295,18 +295,6 @@ static void nfs4_opendata_free(struct nfs4_opendata *p) } } -/* Helper for asynchronous RPC calls */ -static int nfs4_call_async(struct rpc_clnt *clnt, - const struct rpc_call_ops *tk_ops, void *calldata) -{ - struct rpc_task *task; - - if (!(task = rpc_new_task(clnt, RPC_TASK_ASYNC, tk_ops, calldata))) - return -ENOMEM; - rpc_execute(task); - return 0; -} - static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) { sigset_t oldset; @@ -1218,6 +1206,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_closedata *calldata; + struct nfs4_state_owner *sp = state->owner; + struct rpc_task *task; int status = -ENOMEM; calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); @@ -1237,14 +1227,16 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state) calldata->path.mnt = mntget(path->mnt); calldata->path.dentry = dget(path->dentry); - status = nfs4_call_async(server->client, &nfs4_close_ops, calldata); - if (status == 0) - goto out; - - nfs_free_seqid(calldata->arg.seqid); + task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata); + if (IS_ERR(task)) + return PTR_ERR(task); + rpc_put_task(task); + return 0; out_free_calldata: kfree(calldata); out: + nfs4_put_open_state(state); + nfs4_put_state_owner(sp); return status; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index a85138ef67a..5d7ffbfc348 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -375,10 +375,11 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) spin_unlock(&inode->i_lock); spin_unlock(&owner->so_lock); - if (oldstate != newstate && nfs4_do_close(path, state) == 0) - return; - nfs4_put_open_state(state); - nfs4_put_state_owner(owner); + if (oldstate == newstate) { + nfs4_put_open_state(state); + nfs4_put_state_owner(owner); + } else + nfs4_do_close(path, state); } /* diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 73075dec83c..c46d31ca307 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -30,7 +30,6 @@ EXPORT_SYMBOL(rpc_wake_up_next); EXPORT_SYMBOL(rpc_wake_up_task); EXPORT_SYMBOL(rpciod_down); EXPORT_SYMBOL(rpciod_up); -EXPORT_SYMBOL(rpc_new_task); EXPORT_SYMBOL(rpc_wake_up_status); /* RPC client functions */ -- cgit v1.2.3-70-g09d2 From a0356862bcbeb20acf64bc1a82d28a4c5bb957a7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Jun 2007 13:26:15 -0400 Subject: NFS: Fix nfs_reval_fsid() We don't need to revalidate the fsid on the root directory. It suffices to revalidate it on the current directory. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 9 ++++----- fs/nfs/inode.c | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 4948ec1dd9b..c02a7962e69 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -897,14 +897,13 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) return (nd->intent.open.flags & O_EXCL) != 0; } -static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir, - struct nfs_fh *fh, struct nfs_fattr *fattr) +static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr) { struct nfs_server *server = NFS_SERVER(dir); if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) - /* Revalidate fsid on root dir */ - return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode); + /* Revalidate fsid using the parent directory */ + return __nfs_revalidate_inode(server, dir); return 0; } @@ -946,7 +945,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru res = ERR_PTR(error); goto out_unlock; } - error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr); + error = nfs_reval_fsid(dir, &fattr); if (error < 0) { res = ERR_PTR(error); goto out_unlock; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 23ecf0334a1..7bcb3dfa617 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -961,8 +961,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) goto out_changed; server = NFS_SERVER(inode); - /* Update the fsid if and only if this is the root directory */ - if (inode == inode->i_sb->s_root->d_inode + /* Update the fsid? */ + if (S_ISDIR(inode->i_mode) && !nfs_fsid_equal(&server->fsid, &fattr->fsid)) server->fsid = fattr->fsid; -- cgit v1.2.3-70-g09d2 From 83d93f2229348837bf988a1048f7f38789474471 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 7 Jun 2007 09:58:08 -0400 Subject: NFS: Use GFP_HIGHUSER for page allocation in nfs_symlink() nfs_symlink() allocates a GFP_KERNEL page for the pagecache. Most pagecache pages are allocated using GFP_HIGHUSER, and there's no reason not to do that in nfs_symlink() as well. Signed-off-by: Jeff Layton --- fs/nfs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c02a7962e69..0f41678fd7e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1534,7 +1534,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym lock_kernel(); - page = alloc_page(GFP_KERNEL); + page = alloc_page(GFP_HIGHUSER); if (!page) { unlock_kernel(); return -ENOMEM; -- cgit v1.2.3-70-g09d2 From fc6ae3cf482c385a6fe87ba119d399bb85aa670b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Jun 2007 19:13:47 -0400 Subject: NFS: Re-enable forced umounts They disappeared some time around 2.6.18. Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ca20d3cc260..14c7923697d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -430,7 +430,20 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) */ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) { + struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb); + struct rpc_clnt *rpc; + shrink_submounts(vfsmnt, &nfs_automount_list); + + if (!(flags & MNT_FORCE)) + return; + /* -EIO all pending I/O */ + rpc = server->client_acl; + if (!IS_ERR(rpc)) + rpc_killall_tasks(rpc); + rpc = server->client; + if (!IS_ERR(rpc)) + rpc_killall_tasks(rpc); } /* -- cgit v1.2.3-70-g09d2 From aa53ed541a1fec78a78d02afc8b042d040cc080d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 5 Jun 2007 14:49:03 -0400 Subject: NFS4: on a O_EXCL OPEN make sure SETATTR sets the fields holding the verifier The Linux NFS4 client simply skips over the bitmask in an O_EXCL open call and so it doesn't bother to reset any fields that may be holding the verifier. This patch has us save the first two words of the bitmask (which is all the current client has #defines for). The client then later checks this bitmask and turns on the appropriate flags in the sattr->ia_verify field for the following SETATTR call. This patch only currently checks to see if the server used the atime and mtime slots for the verifier (which is what the Linux server uses for this). I'm not sure of what other fields the server could reasonably use, but adding checks for others should be trivial. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 20 ++++++++++++++++++++ fs/nfs/nfs4xdr.c | 9 +++++++-- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 1 + 4 files changed, 29 insertions(+), 2 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3cc75445a68..fee2d14b158 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -942,6 +942,22 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st return res; } +/* + * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-* + * fields corresponding to attributes that were used to store the verifier. + * Make sure we clobber those fields in the later setattr call + */ +static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr) +{ + if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) && + !(sattr->ia_valid & ATTR_ATIME_SET)) + sattr->ia_valid |= ATTR_ATIME; + + if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) && + !(sattr->ia_valid & ATTR_MTIME_SET)) + sattr->ia_valid |= ATTR_MTIME; +} + /* * Returns a referenced nfs4_state */ @@ -973,6 +989,9 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct if (status != 0) goto err_opendata_free; + if (opendata->o_arg.open_flags & O_EXCL) + nfs4_exclusive_attrset(opendata, sattr); + status = -ENOMEM; state = nfs4_opendata_to_nfs4_state(opendata); if (state == NULL) @@ -1784,6 +1803,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, status = nfs4_do_setattr(state->inode, &fattr, sattr, state); if (status == 0) nfs_setattr_update_inode(state->inode, sattr); + nfs_post_op_update_inode(state->inode, &fattr); } if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) status = nfs4_intent_set_file(nd, &path, state); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 8003c91ccb9..1fcca516e6e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -3269,7 +3269,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) { __be32 *p; - uint32_t bmlen; + uint32_t savewords, bmlen, i; int status; status = decode_op_hdr(xdr, OP_OPEN); @@ -3287,7 +3287,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) goto xdr_error; READ_BUF(bmlen << 2); - p += bmlen; + savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE); + for (i = 0; i < savewords; ++i) + READ32(res->attrset[i]); + for (; i < NFS4_BITMAP_SIZE; i++) + res->attrset[i] = 0; + return decode_delegation(xdr, res); xdr_error: dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen); diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 7e7f33a38fc..8726491de15 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -15,6 +15,7 @@ #include +#define NFS4_BITMAP_SIZE 2 #define NFS4_VERIFIER_SIZE 8 #define NFS4_STATEID_SIZE 16 #define NFS4_FHSIZE 128 diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 10c26ed0db7..f7100df3a69 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -144,6 +144,7 @@ struct nfs_openres { nfs4_stateid delegation; __u32 do_recall; __u64 maxsize; + __u32 attrset[NFS4_BITMAP_SIZE]; }; /* -- cgit v1.2.3-70-g09d2 From e2f032e9ef66e33089d09452892696ea97d1dca1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Jun 2007 19:27:00 -0400 Subject: NFS: nfs3_proc_create() should use nfs_post_op_update_inode() Also get rid of a redundant call to nfs_setattr_update_inode(). The call to nfs3_proc_setattr() already takes care of that. Signed-off-by: Trond Myklebust --- fs/nfs/nfs3proc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 45268d6def2..814d886b6aa 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -335,9 +335,7 @@ again: * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ status = nfs3_proc_setattr(dentry, &fattr, sattr); - if (status == 0) - nfs_setattr_update_inode(dentry->d_inode, sattr); - nfs_refresh_inode(dentry->d_inode, &fattr); + nfs_post_op_update_inode(dentry->d_inode, &fattr); dprintk("NFS reply setattr (post-create): %d\n", status); } if (status != 0) -- cgit v1.2.3-70-g09d2 From a50f7951a31d3b976e829250853f89c9d2da32c0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 5 Jun 2007 19:23:43 -0400 Subject: NFS: Fix an Oops in the nfs_access_cache_shrinker() The nfs_access_cache_shrinker may race with nfs_access_zap_cache(). Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 0f41678fd7e..322141f4ab4 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1743,8 +1743,8 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) struct nfs_inode *nfsi; struct nfs_access_entry *cache; - spin_lock(&nfs_access_lru_lock); restart: + spin_lock(&nfs_access_lru_lock); list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { struct inode *inode; @@ -1769,6 +1769,7 @@ remove_lru_entry: clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); } spin_unlock(&inode->i_lock); + spin_unlock(&nfs_access_lru_lock); iput(inode); goto restart; } -- cgit v1.2.3-70-g09d2 From c03b40246123b2ced79e2620d1d2c089bb12369a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 17 Jun 2007 13:26:38 -0400 Subject: NFS: Convert struct nfs_page to use krefs Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 14 ++++++++------ fs/nfs/write.c | 6 +++--- include/linux/nfs_page.h | 10 +++++----- 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index f8a4ba53393..257a7f8b236 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -85,9 +85,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, req->wb_offset = offset; req->wb_pgbase = offset; req->wb_bytes = count; - atomic_set(&req->wb_count, 1); req->wb_context = get_nfs_open_context(ctx); - + kref_init(&req->wb_kref); return req; } @@ -160,11 +159,9 @@ void nfs_clear_request(struct nfs_page *req) * * Note: Should never be called with the spinlock held! */ -void -nfs_release_request(struct nfs_page *req) +static void nfs_free_request(struct kref *kref) { - if (!atomic_dec_and_test(&req->wb_count)) - return; + struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); /* Release struct file or cached credential */ nfs_clear_request(req); @@ -172,6 +169,11 @@ nfs_release_request(struct nfs_page *req) nfs_page_free(req); } +void nfs_release_request(struct nfs_page *req) +{ + kref_put(&req->wb_kref, nfs_free_request); +} + static int nfs_wait_bit_interruptible(void *word) { int ret = 0; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9e7c21da864..e9404328ac0 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -117,7 +117,7 @@ static struct nfs_page *nfs_page_find_request_locked(struct page *page) if (PagePrivate(page)) { req = (struct nfs_page *)page_private(page); if (req != NULL) - atomic_inc(&req->wb_count); + kref_get(&req->wb_kref); } return req; } @@ -398,7 +398,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) if (PageDirty(req->wb_page)) set_bit(PG_NEED_FLUSH, &req->wb_flags); nfsi->npages++; - atomic_inc(&req->wb_count); + kref_get(&req->wb_kref); return 0; } @@ -531,7 +531,7 @@ static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, u next = req->wb_index + 1; BUG_ON(!NFS_WBACK_BUSY(req)); - atomic_inc(&req->wb_count); + kref_get(&req->wb_kref); spin_unlock(&nfsi->req_lock); error = nfs_wait_on_request(req); nfs_release_request(req); diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index bd193af8016..c780e7e39f9 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -16,7 +16,7 @@ #include #include -#include +#include /* * Valid flags for the radix tree @@ -42,7 +42,7 @@ struct nfs_page { unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */ wb_pgbase, /* Start of page data */ wb_bytes; /* Length of request */ - atomic_t wb_count; /* reference count */ + struct kref wb_kref; /* reference count */ unsigned long wb_flags; struct nfs_writeverf wb_verf; /* Commit cookie */ }; @@ -89,7 +89,7 @@ extern void nfs_clear_page_writeback(struct nfs_page *req); /* - * Lock the page of an asynchronous request without incrementing the wb_count + * Lock the page of an asynchronous request without getting a new reference */ static inline int nfs_lock_request_dontget(struct nfs_page *req) @@ -98,14 +98,14 @@ nfs_lock_request_dontget(struct nfs_page *req) } /* - * Lock the page of an asynchronous request + * Lock the page of an asynchronous request and take a reference */ static inline int nfs_lock_request(struct nfs_page *req) { if (test_and_set_bit(PG_BUSY, &req->wb_flags)) return 0; - atomic_inc(&req->wb_count); + kref_get(&req->wb_kref); return 1; } -- cgit v1.2.3-70-g09d2 From 9fd367f0f376ccfb2592eed9be0eece70429894f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 17 Jun 2007 15:10:24 -0400 Subject: NFS cleanup: Rename NFS_PAGE_TAG_WRITEBACK to NFS_PAGE_TAG_LOCKED Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 14 +++++++------- fs/nfs/write.c | 16 ++++++++-------- include/linux/nfs_page.h | 5 ++--- 3 files changed, 17 insertions(+), 18 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 257a7f8b236..23e9dea2090 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -108,29 +108,29 @@ void nfs_unlock_request(struct nfs_page *req) } /** - * nfs_set_page_writeback_locked - Lock a request for writeback + * nfs_set_page_tag_locked - Tag a request as locked * @req: */ -int nfs_set_page_writeback_locked(struct nfs_page *req) +static int nfs_set_page_tag_locked(struct nfs_page *req) { struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); if (!nfs_lock_request(req)) return 0; - radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); + radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); return 1; } /** - * nfs_clear_page_writeback - Unlock request and wake up sleepers + * nfs_clear_page_tag_locked - Clear request tag and wake up sleepers */ -void nfs_clear_page_writeback(struct nfs_page *req) +void nfs_clear_page_tag_locked(struct nfs_page *req) { struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); if (req->wb_page != NULL) { spin_lock(&nfsi->req_lock); - radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); + radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); spin_unlock(&nfsi->req_lock); } nfs_unlock_request(req); @@ -421,7 +421,7 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, idx_start = req->wb_index + 1; if (req->wb_list_head != head) continue; - if (nfs_set_page_writeback_locked(req)) { + if (nfs_set_page_tag_locked(req)) { nfs_list_remove_request(req); nfs_list_add_request(req, dst); res++; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e9404328ac0..754066cc914 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -289,7 +289,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, BUG(); } radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, - NFS_PAGE_TAG_WRITEBACK); + NFS_PAGE_TAG_LOCKED); ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); spin_unlock(req_lock); nfs_pageio_add_request(pgio, req); @@ -524,7 +524,7 @@ static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, u idx_end = idx_start + npages - 1; next = idx_start; - while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { + while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_LOCKED)) { if (req->wb_index > idx_end) break; @@ -759,7 +759,7 @@ static void nfs_writepage_release(struct nfs_page *req) nfs_inode_remove_request(req); } else nfs_end_page_writeback(req->wb_page); - nfs_clear_page_writeback(req); + nfs_clear_page_tag_locked(req); } static inline int flush_task_priority(int how) @@ -888,7 +888,7 @@ out_bad: } nfs_redirty_request(req); nfs_end_page_writeback(req->wb_page); - nfs_clear_page_writeback(req); + nfs_clear_page_tag_locked(req); return -ENOMEM; } @@ -931,7 +931,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i nfs_list_remove_request(req); nfs_redirty_request(req); nfs_end_page_writeback(req->wb_page); - nfs_clear_page_writeback(req); + nfs_clear_page_tag_locked(req); } return -ENOMEM; } @@ -1049,7 +1049,7 @@ remove_request: nfs_end_page_writeback(page); nfs_inode_remove_request(req); next: - nfs_clear_page_writeback(req); + nfs_clear_page_tag_locked(req); } } @@ -1212,7 +1212,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) nfs_list_remove_request(req); nfs_mark_request_commit(req); dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); - nfs_clear_page_writeback(req); + nfs_clear_page_tag_locked(req); } return -ENOMEM; } @@ -1265,7 +1265,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) dprintk(" mismatch\n"); nfs_redirty_request(req); next: - nfs_clear_page_writeback(req); + nfs_clear_page_tag_locked(req); } } diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index c780e7e39f9..042434c39b7 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -21,7 +21,7 @@ /* * Valid flags for the radix tree */ -#define NFS_PAGE_TAG_WRITEBACK 0 +#define NFS_PAGE_TAG_LOCKED 0 /* * Valid flags for a dirty buffer @@ -84,8 +84,7 @@ extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc); extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t); extern int nfs_wait_on_request(struct nfs_page *); extern void nfs_unlock_request(struct nfs_page *req); -extern int nfs_set_page_writeback_locked(struct nfs_page *req); -extern void nfs_clear_page_writeback(struct nfs_page *req); +extern void nfs_clear_page_tag_locked(struct nfs_page *req); /* -- cgit v1.2.3-70-g09d2 From 5c36968343fcd013a3f7ae93f246c2e75596780b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 17 Jun 2007 15:27:42 -0400 Subject: NFS cleanup: speed up nfs_scan_commit using radix tree tags Add a tag for requests that are waiting for a COMMIT Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 14 +++++++------- fs/nfs/write.c | 6 +++++- include/linux/nfs_page.h | 5 +++-- 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 23e9dea2090..ad90cbe7670 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -381,10 +381,10 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) /** * nfs_scan_list - Scan a list for matching requests * @nfsi: NFS inode - * @head: One of the NFS inode request lists * @dst: Destination list * @idx_start: lower bound of page->index to scan * @npages: idx_start + npages sets the upper bound to scan. + * @tag: tag to scan for * * Moves elements from one of the inode request lists. * If the number of requests is set to 0, the entire address_space @@ -392,9 +392,9 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) * The requests are *not* checked to ensure that they form a contiguous set. * You must be holding the inode's req_lock when calling this function */ -int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, +int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst, pgoff_t idx_start, - unsigned int npages) + unsigned int npages, int tag) { struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; struct nfs_page *req; @@ -409,9 +409,9 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, idx_end = idx_start + npages - 1; for (;;) { - found = radix_tree_gang_lookup(&nfsi->nfs_page_tree, + found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&pgvec[0], idx_start, - NFS_SCAN_MAXENTRIES); + NFS_SCAN_MAXENTRIES, tag); if (found <= 0) break; for (i = 0; i < found; i++) { @@ -419,10 +419,10 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, if (req->wb_index > idx_end) goto out; idx_start = req->wb_index + 1; - if (req->wb_list_head != head) - continue; if (nfs_set_page_tag_locked(req)) { nfs_list_remove_request(req); + radix_tree_tag_clear(&nfsi->nfs_page_tree, + req->wb_index, tag); nfs_list_add_request(req, dst); res++; } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 754066cc914..0f779ca12ec 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -462,6 +462,9 @@ nfs_mark_request_commit(struct nfs_page *req) nfs_list_add_request(req, &nfsi->commit); nfsi->ncommit++; set_bit(PG_NEED_COMMIT, &(req)->wb_flags); + radix_tree_tag_set(&nfsi->nfs_page_tree, + req->wb_index, + NFS_PAGE_TAG_COMMIT); spin_unlock(&nfsi->req_lock); inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); __mark_inode_dirty(inode, I_DIRTY_DATASYNC); @@ -575,7 +578,8 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, u int res = 0; if (nfsi->ncommit != 0) { - res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages); + res = nfs_scan_list(nfsi, dst, idx_start, npages, + NFS_PAGE_TAG_COMMIT); nfsi->ncommit -= res; if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 042434c39b7..481a42105d6 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -22,6 +22,7 @@ * Valid flags for the radix tree */ #define NFS_PAGE_TAG_LOCKED 0 +#define NFS_PAGE_TAG_COMMIT 1 /* * Valid flags for a dirty buffer @@ -71,8 +72,8 @@ extern void nfs_clear_request(struct nfs_page *req); extern void nfs_release_request(struct nfs_page *req); -extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst, - pgoff_t idx_start, unsigned int npages); +extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst, + pgoff_t idx_start, unsigned int npages, int tag); extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc, struct inode *inode, int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int), -- cgit v1.2.3-70-g09d2 From 2aefa104313996d1a9582476cee53d1296c834bf Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 17 Jun 2007 15:40:59 -0400 Subject: NFS: Remove the redundant 'dirty' and 'commit' lists from nfs_inode Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 3 --- fs/nfs/write.c | 3 --- include/linux/nfs_fs.h | 5 +---- include/linux/nfs_page.h | 5 +---- 4 files changed, 2 insertions(+), 14 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 7bcb3dfa617..e7d2bba900b 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1149,14 +1149,11 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag inode_init_once(&nfsi->vfs_inode); spin_lock_init(&nfsi->req_lock); - INIT_LIST_HEAD(&nfsi->dirty); - INIT_LIST_HEAD(&nfsi->commit); INIT_LIST_HEAD(&nfsi->open_files); INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); atomic_set(&nfsi->data_updates, 0); - nfsi->ndirty = 0; nfsi->ncommit = 0; nfsi->npages = 0; nfs4_init_once(nfsi); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0f779ca12ec..9ef9ec746bf 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -459,7 +459,6 @@ nfs_mark_request_commit(struct nfs_page *req) struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&nfsi->req_lock); - nfs_list_add_request(req, &nfsi->commit); nfsi->ncommit++; set_bit(PG_NEED_COMMIT, &(req)->wb_flags); radix_tree_tag_set(&nfsi->nfs_page_tree, @@ -581,8 +580,6 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, u res = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); nfsi->ncommit -= res; - if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) - printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); } return res; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 07eea8f64ec..a9420547673 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -156,12 +156,9 @@ struct nfs_inode { * This is the list of dirty unwritten pages. */ spinlock_t req_lock; - struct list_head dirty; - struct list_head commit; struct radix_tree_root nfs_page_tree; - unsigned int ndirty, - ncommit, + unsigned int ncommit, npages; /* Open contexts for shared mmap writes */ diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 481a42105d6..78e60798d10 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -34,8 +34,7 @@ struct nfs_inode; struct nfs_page { - struct list_head wb_list, /* Defines state of page: */ - *wb_list_head; /* read/write/commit */ + struct list_head wb_list; /* Defines state of page: */ 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 */ @@ -118,7 +117,6 @@ static inline void nfs_list_add_request(struct nfs_page *req, struct list_head *head) { list_add_tail(&req->wb_list, head); - req->wb_list_head = head; } @@ -132,7 +130,6 @@ nfs_list_remove_request(struct nfs_page *req) if (list_empty(&req->wb_list)) return; list_del_init(&req->wb_list); - req->wb_list_head = NULL; } static inline struct nfs_page * -- cgit v1.2.3-70-g09d2 From dce34ce298d85b81630401f4feb4bd7ac77fe9c7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 17 Jun 2007 15:47:53 -0400 Subject: NFS: Prevent integer overflow in nfs_scan_list() Also ensure that nfs_inode ncommit and npages are large enough to represent all possible values for the number of pages. Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 2 ++ include/linux/nfs_fs.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index ad90cbe7670..68f6bf12200 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -425,6 +425,8 @@ int nfs_scan_list(struct nfs_inode *nfsi, req->wb_index, tag); nfs_list_add_request(req, dst); res++; + if (res == INT_MAX) + goto out; } } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index a9420547673..750708ccd70 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -158,7 +158,7 @@ struct nfs_inode { spinlock_t req_lock; struct radix_tree_root nfs_page_tree; - unsigned int ncommit, + unsigned long ncommit, npages; /* Open contexts for shared mmap writes */ -- cgit v1.2.3-70-g09d2 From edc05fc1c24ba49dae585da1b2a22686f0b221f0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 17 Jun 2007 16:02:34 -0400 Subject: NFS: reduce latency by using conditional rescheduling in nfs_scan_list Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 68f6bf12200..8d2642f24b8 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -429,7 +429,8 @@ int nfs_scan_list(struct nfs_inode *nfsi, goto out; } } - + /* for latency reduction */ + cond_resched_lock(&nfsi->req_lock); } out: return res; -- cgit v1.2.3-70-g09d2 From 3bec63db55463365110d00721ed60a31e4614cb6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 17 Jun 2007 16:02:44 -0400 Subject: NFS: Convert struct nfs_open_context to use a kref Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 40 +++++++++++++++++++++++----------------- include/linux/nfs_fs.h | 3 ++- 2 files changed, 25 insertions(+), 18 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index e7d2bba900b..01fc8ab0c56 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -461,7 +461,6 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (ctx != NULL) { - atomic_set(&ctx->count, 1); ctx->path.dentry = dget(dentry); ctx->path.mnt = mntget(mnt); ctx->cred = get_rpccred(cred); @@ -469,6 +468,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str ctx->lockowner = current->files; ctx->error = 0; ctx->dir_cookie = 0; + kref_init(&ctx->kref); } return ctx; } @@ -476,27 +476,33 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) { if (ctx != NULL) - atomic_inc(&ctx->count); + kref_get(&ctx->kref); return ctx; } -void put_nfs_open_context(struct nfs_open_context *ctx) +static void nfs_free_open_context(struct kref *kref) { - if (atomic_dec_and_test(&ctx->count)) { - if (!list_empty(&ctx->list)) { - struct inode *inode = ctx->path.dentry->d_inode; - spin_lock(&inode->i_lock); - list_del(&ctx->list); - spin_unlock(&inode->i_lock); - } - if (ctx->state != NULL) - nfs4_close_state(&ctx->path, ctx->state, ctx->mode); - if (ctx->cred != NULL) - put_rpccred(ctx->cred); - dput(ctx->path.dentry); - mntput(ctx->path.mnt); - kfree(ctx); + struct nfs_open_context *ctx = container_of(kref, + struct nfs_open_context, kref); + + if (!list_empty(&ctx->list)) { + struct inode *inode = ctx->path.dentry->d_inode; + spin_lock(&inode->i_lock); + list_del(&ctx->list); + spin_unlock(&inode->i_lock); } + if (ctx->state != NULL) + nfs4_close_state(&ctx->path, ctx->state, ctx->mode); + if (ctx->cred != NULL) + put_rpccred(ctx->cred); + dput(ctx->path.dentry); + mntput(ctx->path.mnt); + kfree(ctx); +} + +void put_nfs_open_context(struct nfs_open_context *ctx) +{ + kref_put(&ctx->kref, nfs_free_open_context); } /* diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 750708ccd70..bf24151d63b 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -30,6 +30,7 @@ #ifdef __KERNEL__ #include +#include #include #include #include @@ -70,7 +71,7 @@ struct nfs_access_entry { struct nfs4_state; struct nfs_open_context { - atomic_t count; + struct kref kref; struct path path; struct rpc_cred *cred; struct nfs4_state *state; -- cgit v1.2.3-70-g09d2 From c6d00e639bdec5f33460bc95bae4efda7177a6ed Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 17 Jun 2007 16:02:44 -0400 Subject: NFSv4: Convert struct nfs4_opendata to use struct kref Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index fee2d14b158..d90209e7958 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -214,7 +214,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) } struct nfs4_opendata { - atomic_t count; + struct kref kref; struct nfs_openargs o_arg; struct nfs_openres o_res; struct nfs_open_confirmargs c_arg; @@ -245,7 +245,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); if (p->o_arg.seqid == NULL) goto err_free; - atomic_set(&p->count, 1); p->path.mnt = mntget(path->mnt); p->path.dentry = dget(path->dentry); p->dir = parent; @@ -275,6 +274,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, p->c_arg.fh = &p->o_res.fh; p->c_arg.stateid = &p->o_res.stateid; p->c_arg.seqid = p->o_arg.seqid; + kref_init(&p->kref); return p; err_free: kfree(p); @@ -283,16 +283,23 @@ err: return NULL; } -static void nfs4_opendata_free(struct nfs4_opendata *p) +static void nfs4_opendata_free(struct kref *kref) { - if (p != NULL && atomic_dec_and_test(&p->count)) { - nfs_free_seqid(p->o_arg.seqid); - nfs4_put_state_owner(p->owner); - dput(p->dir); - dput(p->path.dentry); - mntput(p->path.mnt); - kfree(p); - } + struct nfs4_opendata *p = container_of(kref, + struct nfs4_opendata, kref); + + nfs_free_seqid(p->o_arg.seqid); + nfs4_put_state_owner(p->owner); + dput(p->dir); + dput(p->path.dentry); + mntput(p->path.mnt); + kfree(p); +} + +static void nfs4_opendata_put(struct nfs4_opendata *p) +{ + if (p != NULL) + kref_put(&p->kref, nfs4_opendata_free); } static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) @@ -476,7 +483,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh); opendata->o_arg.u.delegation_type = delegation_type; status = nfs4_open_recover(opendata, state); - nfs4_opendata_free(opendata); + nfs4_opendata_put(opendata); return status; } @@ -522,7 +529,7 @@ static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs memcpy(opendata->o_arg.u.delegation.data, state->stateid.data, sizeof(opendata->o_arg.u.delegation.data)); ret = nfs4_open_recover(opendata, state); - nfs4_opendata_free(opendata); + nfs4_opendata_put(opendata); return ret; } @@ -593,7 +600,7 @@ static void nfs4_open_confirm_release(void *calldata) if (state != NULL) nfs4_close_state(&data->path, state, data->o_arg.open_flags); out_free: - nfs4_opendata_free(data); + nfs4_opendata_put(data); } static const struct rpc_call_ops nfs4_open_confirm_ops = { @@ -611,7 +618,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) struct rpc_task *task; int status; - atomic_inc(&data->count); + kref_get(&data->kref); /* * If rpc_run_task() ends up calling ->rpc_release(), we * want to ensure that it takes the 'error' code path. @@ -696,7 +703,7 @@ static void nfs4_open_release(void *calldata) if (state != NULL) nfs4_close_state(&data->path, state, data->o_arg.open_flags); out_free: - nfs4_opendata_free(data); + nfs4_opendata_put(data); } static const struct rpc_call_ops nfs4_open_ops = { @@ -717,7 +724,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) struct rpc_task *task; int status; - atomic_inc(&data->count); + kref_get(&data->kref); /* * If rpc_run_task() ends up calling ->rpc_release(), we * want to ensure that it takes the 'error' code path. @@ -826,7 +833,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s nfs4_drop_state_owner(state->owner); d_drop(ctx->path.dentry); } - nfs4_opendata_free(opendata); + nfs4_opendata_put(opendata); return ret; } @@ -987,7 +994,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct status = _nfs4_proc_open(opendata); if (status != 0) - goto err_opendata_free; + goto err_opendata_put; if (opendata->o_arg.open_flags & O_EXCL) nfs4_exclusive_attrset(opendata, sattr); @@ -995,16 +1002,16 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct status = -ENOMEM; state = nfs4_opendata_to_nfs4_state(opendata); if (state == NULL) - goto err_opendata_free; + goto err_opendata_put; if (opendata->o_res.delegation_type != 0) nfs_inode_set_delegation(state->inode, cred, &opendata->o_res); - nfs4_opendata_free(opendata); + nfs4_opendata_put(opendata); nfs4_put_state_owner(sp); up_read(&clp->cl_sem); *res = state; return 0; -err_opendata_free: - nfs4_opendata_free(opendata); +err_opendata_put: + nfs4_opendata_put(opendata); err_release_rwsem: up_read(&clp->cl_sem); err_put_state_owner: -- cgit v1.2.3-70-g09d2 From 90c5755ff5111ffdcca10a1e8a823dba29f37b6d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 9 Jun 2007 19:49:36 -0400 Subject: SUNRPC: Kill rpc_clnt->cl_oneshot Replace it with explicit calls to rpc_shutdown_client() or rpc_destroy_client() (for the case of asynchronous calls). Signed-off-by: Trond Myklebust --- fs/lockd/mon.c | 2 +- fs/nfs/mount_clnt.c | 4 ++-- include/linux/sunrpc/clnt.h | 10 ++++------ net/sunrpc/clnt.c | 10 +--------- net/sunrpc/rpcb_clnt.c | 6 ++++-- net/sunrpc/sched.c | 14 ++------------ 6 files changed, 14 insertions(+), 32 deletions(-) (limited to 'fs/nfs') diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 2102e2d0134..3353ed8421a 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -61,6 +61,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) status); else status = 0; + rpc_shutdown_client(clnt); out: return status; } @@ -138,7 +139,6 @@ nsm_create(void) .program = &nsm_program, .version = SM_VERSION, .authflavor = RPC_AUTH_NULL, - .flags = (RPC_CLNT_CREATE_ONESHOT), }; return rpc_create(&args); diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index ca5a266a314..878d7a5cb6d 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -69,6 +69,7 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; status = rpc_call_sync(mnt_clnt, &msg, 0); + rpc_shutdown_client(mnt_clnt); return status < 0? status : (result.status? -EACCES : 0); } @@ -84,8 +85,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, .program = &mnt_program, .version = version, .authflavor = RPC_AUTH_UNIX, - .flags = (RPC_CLNT_CREATE_ONESHOT | - RPC_CLNT_CREATE_INTR), + .flags = RPC_CLNT_CREATE_INTR, }; return rpc_create(&args); diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index ab3ef6d629a..fe7ea65ed0a 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -44,8 +44,7 @@ struct rpc_clnt { unsigned int cl_softrtry : 1,/* soft timeouts */ cl_intr : 1,/* interruptible */ cl_discrtry : 1,/* disconnect before retry */ - cl_autobind : 1,/* use getport() */ - cl_oneshot : 1;/* dispose after use */ + cl_autobind : 1;/* use getport() */ struct rpc_rtt * cl_rtt; /* RTO estimator data */ @@ -112,10 +111,9 @@ struct rpc_create_args { #define RPC_CLNT_CREATE_HARDRTRY (1UL << 0) #define RPC_CLNT_CREATE_INTR (1UL << 1) #define RPC_CLNT_CREATE_AUTOBIND (1UL << 2) -#define RPC_CLNT_CREATE_ONESHOT (1UL << 3) -#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4) -#define RPC_CLNT_CREATE_NOPING (1UL << 5) -#define RPC_CLNT_CREATE_DISCRTRY (1UL << 6) +#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 3) +#define RPC_CLNT_CREATE_NOPING (1UL << 4) +#define RPC_CLNT_CREATE_DISCRTRY (1UL << 5) struct rpc_clnt *rpc_create(struct rpc_create_args *args); struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index fb65249538d..34662dfa9cc 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -249,8 +249,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) clnt->cl_intr = 1; if (args->flags & RPC_CLNT_CREATE_AUTOBIND) clnt->cl_autobind = 1; - if (args->flags & RPC_CLNT_CREATE_ONESHOT) - clnt->cl_oneshot = 1; if (args->flags & RPC_CLNT_CREATE_DISCRTRY) clnt->cl_discrtry = 1; @@ -285,7 +283,6 @@ rpc_clone_client(struct rpc_clnt *clnt) new->cl_xprt = xprt_get(clnt->cl_xprt); /* Turn off autobind on clones */ new->cl_autobind = 0; - new->cl_oneshot = 0; INIT_LIST_HEAD(&new->cl_tasks); spin_lock_init(&new->cl_lock); rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); @@ -304,8 +301,7 @@ out_no_clnt: /* * Properly shut down an RPC client, terminating all outstanding - * requests. Note that we must be certain that cl_oneshot is cleared, - * or else the client would be destroyed when the last task releases it. + * requests. */ int rpc_shutdown_client(struct rpc_clnt *clnt) @@ -314,8 +310,6 @@ rpc_shutdown_client(struct rpc_clnt *clnt) clnt->cl_protname, clnt->cl_server); while (!list_empty(&clnt->cl_tasks)) { - /* Don't let rpc_release_client destroy us */ - clnt->cl_oneshot = 0; rpc_killall_tasks(clnt); wait_event_timeout(destroy_wait, list_empty(&clnt->cl_tasks), 1*HZ); @@ -366,8 +360,6 @@ rpc_release_client(struct rpc_clnt *clnt) if (list_empty(&clnt->cl_tasks)) wake_up(&destroy_wait); - if (clnt->cl_oneshot) - rpc_destroy_client(clnt); kref_put(&clnt->cl_kref, rpc_free_client); } diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 6c7aa8a1f0c..00853a32649 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -184,8 +184,7 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, .program = &rpcb_program, .version = version, .authflavor = RPC_AUTH_UNIX, - .flags = (RPC_CLNT_CREATE_ONESHOT | - RPC_CLNT_CREATE_NOPING), + .flags = RPC_CLNT_CREATE_NOPING, }; ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT); @@ -238,6 +237,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) error = rpc_call_sync(rpcb_clnt, &msg, 0); + rpc_shutdown_client(rpcb_clnt); if (error < 0) printk(KERN_WARNING "RPC: failed to contact local rpcbind " "server (errno %d).\n", -error); @@ -286,6 +286,7 @@ int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog, return PTR_ERR(rpcb_clnt); status = rpc_call_sync(rpcb_clnt, &msg, 0); + rpc_shutdown_client(rpcb_clnt); if (status >= 0) { if (map.r_port != 0) @@ -379,6 +380,7 @@ void rpcb_getport(struct rpc_task *task) } child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map); + rpc_destroy_client(rpcb_clnt); if (IS_ERR(child)) { status = -EIO; dprintk("RPC: %5u rpcb_getport rpc_run_task failed\n", diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index bb12983580a..d95fe4e40eb 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -876,9 +876,7 @@ static void rpc_free_task(struct rcu_head *rcu) } /* - * Create a new task for the specified client. We have to - * clean up after an allocation failure, as the client may - * have specified "oneshot". + * Create a new task for the specified client. */ struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata) { @@ -886,7 +884,7 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc task = rpc_alloc_task(); if (!task) - goto cleanup; + goto out; rpc_init_task(task, clnt, flags, tk_ops, calldata); @@ -894,14 +892,6 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc task->tk_flags |= RPC_TASK_DYNAMIC; out: return task; - -cleanup: - /* Check whether to release the client */ - if (clnt) { - kref_get(&clnt->cl_kref); /* pretend we were used ... */ - rpc_release_client(clnt); - } - goto out; } -- cgit v1.2.3-70-g09d2 From f61534dfd38f895b203e2aadaba04f21a992ca8c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 14 Jun 2007 17:31:58 -0400 Subject: SUNRPC: Remove redundant calls to rpciod_up()/rpciod_down() Signed-off-by: Trond Myklebust --- fs/lockd/svc.c | 6 ------ fs/nfs/client.c | 15 --------------- fs/nfsd/nfs4callback.c | 12 +++--------- fs/nfsd/nfs4state.c | 1 - include/linux/nfs_fs_sb.h | 1 - net/sunrpc/sunrpc_syms.c | 2 -- 6 files changed, 3 insertions(+), 34 deletions(-) (limited to 'fs/nfs') diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 126b1bf02c0..26809325469 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -123,9 +123,6 @@ lockd(struct svc_rqst *rqstp) /* Process request with signals blocked, but allow SIGKILL. */ allow_signal(SIGKILL); - /* kick rpciod */ - rpciod_up(); - dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); if (!nlm_timeout) @@ -202,9 +199,6 @@ lockd(struct svc_rqst *rqstp) /* Exit the RPC thread */ svc_exit_thread(rqstp); - /* release rpciod */ - rpciod_down(); - /* Release module */ unlock_kernel(); module_put_and_exit(0); diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 881fa490092..71d4c4cdac5 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -102,19 +102,10 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, int nfsversion) { struct nfs_client *clp; - int error; if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) goto error_0; - error = rpciod_up(); - if (error < 0) { - dprintk("%s: couldn't start rpciod! Error = %d\n", - __FUNCTION__, error); - goto error_1; - } - __set_bit(NFS_CS_RPCIOD, &clp->cl_res_state); - if (nfsversion == 4) { if (nfs_callback_up() < 0) goto error_2; @@ -154,9 +145,6 @@ error_3: if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) nfs_callback_down(); error_2: - rpciod_down(); - __clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state); -error_1: kfree(clp); error_0: return NULL; @@ -198,9 +186,6 @@ static void nfs_free_client(struct nfs_client *clp) if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) nfs_callback_down(); - if (__test_and_clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state)) - rpciod_down(); - kfree(clp->cl_hostname); kfree(clp); diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 864090edc28..6b1b487db1e 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -429,29 +429,23 @@ nfsd4_probe_callback(struct nfs4_client *clp) goto out_err; } - /* Kick rpciod, put the call on the wire. */ - if (rpciod_up() != 0) - goto out_clnt; - /* the task holds a reference to the nfs4_client struct */ atomic_inc(&clp->cl_count); msg.rpc_cred = nfsd4_lookupcred(clp,0); if (IS_ERR(msg.rpc_cred)) - goto out_rpciod; + goto out_release_clp; status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); put_rpccred(msg.rpc_cred); if (status != 0) { dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n"); - goto out_rpciod; + goto out_release_clp; } return; -out_rpciod: +out_release_clp: atomic_dec(&clp->cl_count); - rpciod_down(); -out_clnt: rpc_shutdown_client(cb->cb_client); out_err: cb->cb_client = NULL; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3cc8ce422ab..8c52913d7cb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -378,7 +378,6 @@ shutdown_callback_client(struct nfs4_client *clp) if (clnt) { clp->cl_callback.cb_client = NULL; rpc_shutdown_client(clnt); - rpciod_down(); } } diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 52b4378311c..144d955dc46 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -16,7 +16,6 @@ struct nfs_client { #define NFS_CS_INITING 1 /* busy initialising */ int cl_nfsversion; /* NFS protocol version */ unsigned long cl_res_state; /* NFS resources state */ -#define NFS_CS_RPCIOD 0 /* - rpciod started */ #define NFS_CS_CALLBACK 1 /* - callback started */ #define NFS_CS_IDMAP 2 /* - idmap started */ #define NFS_CS_RENEWD 3 /* - renewd started */ diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 02e83e15fef..b99b11b1146 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -28,8 +28,6 @@ EXPORT_SYMBOL(rpc_init_task); EXPORT_SYMBOL(rpc_sleep_on); EXPORT_SYMBOL(rpc_wake_up_next); EXPORT_SYMBOL(rpc_wake_up_task); -EXPORT_SYMBOL(rpciod_down); -EXPORT_SYMBOL(rpciod_up); EXPORT_SYMBOL(rpc_wake_up_status); /* RPC client functions */ -- cgit v1.2.3-70-g09d2 From 1be27f36601973815171db684c711d30557cf50c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 27 Jun 2007 14:29:04 -0400 Subject: SUNRPC: Remove the tk_auth macro... We should almost always be deferencing the rpc_auth struct by means of the credential's cr_auth field instead of the rpc_clnt->cl_auth anyway. Fix up that historical mistake, and remove the macro that propagated it. Signed-off-by: Trond Myklebust --- fs/nfs/nfs2xdr.c | 6 +++--- fs/nfs/nfs3xdr.c | 8 ++++---- fs/nfs/nfs4xdr.c | 10 +++++----- include/linux/sunrpc/sched.h | 1 - net/sunrpc/auth.c | 25 +++++++++++++------------ net/sunrpc/auth_gss/auth_gss.c | 4 ++-- net/sunrpc/auth_unix.c | 2 +- net/sunrpc/clnt.c | 2 +- 8 files changed, 29 insertions(+), 29 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index cd3ca7b5d3d..7fcc78f2aa7 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -223,7 +223,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args) static int nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; unsigned int replen; u32 offset = (u32)args->offset; u32 count = args->count; @@ -380,7 +380,7 @@ static int nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args) { struct rpc_task *task = req->rq_task; - struct rpc_auth *auth = task->tk_auth; + struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth; unsigned int replen; u32 count = args->count; @@ -541,7 +541,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) static int nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; unsigned int replen; p = xdr_encode_fhandle(p, args->fh); diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index b51df8eb9f0..b4647a22f34 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -319,7 +319,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *arg static int nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; unsigned int replen; u32 count = args->count; @@ -458,7 +458,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args) static int nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; unsigned int replen; u32 count = args->count; @@ -643,7 +643,7 @@ static int nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p, struct nfs3_getaclargs *args) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; unsigned int replen; p = xdr_encode_fhandle(p, args->fh); @@ -773,7 +773,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) static int nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; unsigned int replen; p = xdr_encode_fhandle(p, args->fh); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1fcca516e6e..859b1363325 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1071,7 +1071,7 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; uint32_t attrs[2] = { FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, FATTR4_WORD1_MOUNTED_ON_FILEID, @@ -1117,7 +1117,7 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; unsigned int replen; __be32 *p; @@ -1735,7 +1735,7 @@ out: */ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; struct xdr_stream xdr; struct compound_hdr hdr = { .nops = 2, @@ -1795,7 +1795,7 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, struct nfs_getaclargs *args) { struct xdr_stream xdr; - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; struct compound_hdr hdr = { .nops = 2, }; @@ -2030,7 +2030,7 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs struct compound_hdr hdr = { .nops = 3, }; - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; int replen; int status; diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 3387b008cdf..8ea077db009 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -98,7 +98,6 @@ struct rpc_task { unsigned short tk_pid; /* debugging aid */ #endif }; -#define tk_auth tk_client->cl_auth #define tk_xprt tk_client->cl_xprt /* support walking a list of tasks on a wait queue */ diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 81f4c776c55..74baf87ccff 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -371,7 +371,7 @@ EXPORT_SYMBOL(rpcauth_init_cred); struct rpc_cred * rpcauth_bindcred(struct rpc_task *task) { - struct rpc_auth *auth = task->tk_auth; + struct rpc_auth *auth = task->tk_client->cl_auth; struct auth_cred acred = { .uid = current->fsuid, .gid = current->fsgid, @@ -381,7 +381,7 @@ rpcauth_bindcred(struct rpc_task *task) int flags = 0; dprintk("RPC: %5u looking up %s cred\n", - task->tk_pid, task->tk_auth->au_ops->au_name); + task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); get_group_info(acred.group_info); if (task->tk_flags & RPC_TASK_ROOTCREDS) flags |= RPCAUTH_LOOKUP_ROOTCREDS; @@ -397,11 +397,12 @@ rpcauth_bindcred(struct rpc_task *task) void rpcauth_holdcred(struct rpc_task *task) { - dprintk("RPC: %5u holding %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, - task->tk_msg.rpc_cred); - if (task->tk_msg.rpc_cred) - get_rpccred(task->tk_msg.rpc_cred); + struct rpc_cred *cred = task->tk_msg.rpc_cred; + if (cred != NULL) { + get_rpccred(cred); + dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, + cred->cr_auth->au_ops->au_name, cred); + } } void @@ -441,7 +442,7 @@ rpcauth_unbindcred(struct rpc_task *task) struct rpc_cred *cred = task->tk_msg.rpc_cred; dprintk("RPC: %5u releasing %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, cred); + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); put_rpccred(cred); task->tk_msg.rpc_cred = NULL; @@ -453,7 +454,7 @@ rpcauth_marshcred(struct rpc_task *task, __be32 *p) struct rpc_cred *cred = task->tk_msg.rpc_cred; dprintk("RPC: %5u marshaling %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, cred); + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); return cred->cr_ops->crmarshal(task, p); } @@ -464,7 +465,7 @@ rpcauth_checkverf(struct rpc_task *task, __be32 *p) struct rpc_cred *cred = task->tk_msg.rpc_cred; dprintk("RPC: %5u validating %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, cred); + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); return cred->cr_ops->crvalidate(task, p); } @@ -505,7 +506,7 @@ rpcauth_refreshcred(struct rpc_task *task) int err; dprintk("RPC: %5u refreshing %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, cred); + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); err = cred->cr_ops->crrefresh(task); if (err < 0) @@ -519,7 +520,7 @@ rpcauth_invalcred(struct rpc_task *task) struct rpc_cred *cred = task->tk_msg.rpc_cred; dprintk("RPC: %5u invalidating %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, cred); + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); if (cred) clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); } diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 15da6f82db3..debcda86467 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -906,7 +906,7 @@ gss_validate(struct rpc_task *task, __be32 *p) goto out_bad; /* We leave it to unwrap to calculate au_rslack. For now we just * calculate the length of the verifier: */ - task->tk_auth->au_verfsize = XDR_QUADLEN(len) + 2; + cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2; gss_put_ctx(ctx); dprintk("RPC: %5u gss_validate: gss_verify_mic succeeded.\n", task->tk_pid); @@ -1206,7 +1206,7 @@ gss_unwrap_resp(struct rpc_task *task, break; } /* take into account extra slack for integrity and privacy cases: */ - task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp) + cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp) + (savedlen - head->iov_len); out_decode: status = decode(rqstp, p, obj); diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index d9c50d810d1..5ed91e5bcee 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -204,7 +204,7 @@ unx_validate(struct rpc_task *task, __be32 *p) printk("RPC: giant verf size: %u\n", size); return NULL; } - task->tk_auth->au_rslack = (size >> 2) + 2; + task->tk_msg.rpc_cred->cr_auth->au_rslack = (size >> 2) + 2; p += (size >> 2); return p; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 28a789419f6..50af8bbe7f2 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -787,7 +787,7 @@ call_reserveresult(struct rpc_task *task) static void call_allocate(struct rpc_task *task) { - unsigned int slack = task->tk_auth->au_cslack; + unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack; struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = task->tk_xprt; struct rpc_procinfo *proc = task->tk_msg.rpc_proc; -- cgit v1.2.3-70-g09d2 From 4e56e082dd89266d320ccfbc7bd0102186a765ac Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 1 Jul 2007 18:13:52 -0400 Subject: NFSv4: Clean up _nfs4_proc_lookup() vs _nfs4_proc_lookupfh() They differ only slightly in the arguments they take. Why have they not been merged? Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d90209e7958..84d0b7e0dd6 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1592,8 +1592,6 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, dprintk("NFS call lookupfh %s\n", name->name); status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply lookupfh: %d\n", status); - if (status == -NFS4ERR_MOVED) - status = -EREMOTE; return status; } @@ -1604,10 +1602,13 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, struct nfs4_exception exception = { }; int err; do { - err = nfs4_handle_exception(server, - _nfs4_proc_lookupfh(server, dirfh, name, - fhandle, fattr), - &exception); + err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr); + /* FIXME: !!!! */ + if (err == -NFS4ERR_MOVED) { + err = -EREMOTE; + break; + } + err = nfs4_handle_exception(server, err, &exception); } while (exception.retry); return err; } @@ -1615,28 +1616,10 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - int status; - struct nfs_server *server = NFS_SERVER(dir); - struct nfs4_lookup_arg args = { - .bitmask = server->attr_bitmask, - .dir_fh = NFS_FH(dir), - .name = name, - }; - struct nfs4_lookup_res res = { - .server = server, - .fattr = fattr, - .fh = fhandle, - }; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], - .rpc_argp = &args, - .rpc_resp = &res, - }; - - nfs_fattr_init(fattr); + int status; dprintk("NFS call lookup %s\n", name->name); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); if (status == -NFS4ERR_MOVED) status = nfs4_get_referral(dir, name, fattr, fhandle); dprintk("NFS reply lookup: %d\n", status); -- cgit v1.2.3-70-g09d2 From 587142f85f796cf0b823dd3080e815f02ff6b952 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 2 Jul 2007 09:57:54 -0400 Subject: NFS: Replace NFS_I(inode)->req_lock with inode->i_lock There is no justification for keeping a special spinlock for the exclusive use of the NFS writeback code. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 1 - fs/nfs/pagelist.c | 11 ++++--- fs/nfs/write.c | 84 ++++++++++++++++++++++++-------------------------- include/linux/nfs_fs.h | 1 - 4 files changed, 46 insertions(+), 51 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 01fc8ab0c56..9d5124166d2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1154,7 +1154,6 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag struct nfs_inode *nfsi = (struct nfs_inode *) foo; inode_init_once(&nfsi->vfs_inode); - spin_lock_init(&nfsi->req_lock); INIT_LIST_HEAD(&nfsi->open_files); INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 8d2642f24b8..f56dae5216f 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -126,12 +126,13 @@ static int nfs_set_page_tag_locked(struct nfs_page *req) */ void nfs_clear_page_tag_locked(struct nfs_page *req) { - struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); + struct inode *inode = req->wb_context->path.dentry->d_inode; + struct nfs_inode *nfsi = NFS_I(inode); if (req->wb_page != NULL) { - spin_lock(&nfsi->req_lock); + spin_lock(&inode->i_lock); radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); } nfs_unlock_request(req); } @@ -390,7 +391,7 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) * If the number of requests is set to 0, the entire address_space * starting at index idx_start, is scanned. * The requests are *not* checked to ensure that they form a contiguous set. - * You must be holding the inode's req_lock when calling this function + * You must be holding the inode's i_lock when calling this function */ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst, pgoff_t idx_start, @@ -430,7 +431,7 @@ int nfs_scan_list(struct nfs_inode *nfsi, } } /* for latency reduction */ - cond_resched_lock(&nfsi->req_lock); + cond_resched_lock(&nfsi->vfs_inode.i_lock); } out: return res; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9ef9ec746bf..73ac992ece8 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -124,12 +124,12 @@ static struct nfs_page *nfs_page_find_request_locked(struct page *page) static struct nfs_page *nfs_page_find_request(struct page *page) { + struct inode *inode = page->mapping->host; struct nfs_page *req = NULL; - spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; - spin_lock(req_lock); + spin_lock(&inode->i_lock); req = nfs_page_find_request_locked(page); - spin_unlock(req_lock); + spin_unlock(&inode->i_lock); return req; } @@ -251,16 +251,16 @@ static void nfs_end_page_writeback(struct page *page) static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, struct page *page) { + struct inode *inode = page->mapping->host; + struct nfs_inode *nfsi = NFS_I(inode); struct nfs_page *req; - struct nfs_inode *nfsi = NFS_I(page->mapping->host); - spinlock_t *req_lock = &nfsi->req_lock; int ret; - spin_lock(req_lock); + spin_lock(&inode->i_lock); for(;;) { req = nfs_page_find_request_locked(page); if (req == NULL) { - spin_unlock(req_lock); + spin_unlock(&inode->i_lock); return 1; } if (nfs_lock_request_dontget(req)) @@ -270,28 +270,28 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, * succeed provided that someone hasn't already marked the * request as dirty (in which case we don't care). */ - spin_unlock(req_lock); + spin_unlock(&inode->i_lock); ret = nfs_wait_on_request(req); nfs_release_request(req); if (ret != 0) return ret; - spin_lock(req_lock); + spin_lock(&inode->i_lock); } if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { /* This request is marked for commit */ - spin_unlock(req_lock); + spin_unlock(&inode->i_lock); nfs_unlock_request(req); nfs_pageio_complete(pgio); return 1; } if (nfs_set_page_writeback(page) != 0) { - spin_unlock(req_lock); + spin_unlock(&inode->i_lock); BUG(); } radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); - spin_unlock(req_lock); + spin_unlock(&inode->i_lock); nfs_pageio_add_request(pgio, req); return ret; } @@ -412,7 +412,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) BUG_ON (!NFS_WBACK_BUSY(req)); - spin_lock(&nfsi->req_lock); + spin_lock(&inode->i_lock); set_page_private(req->wb_page, 0); ClearPagePrivate(req->wb_page); radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); @@ -420,11 +420,11 @@ static void nfs_inode_remove_request(struct nfs_page *req) __set_page_dirty_nobuffers(req->wb_page); nfsi->npages--; if (!nfsi->npages) { - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); nfs_end_data_update(inode); iput(inode); } else - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); nfs_clear_request(req); nfs_release_request(req); } @@ -458,13 +458,13 @@ nfs_mark_request_commit(struct nfs_page *req) struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); - spin_lock(&nfsi->req_lock); + spin_lock(&inode->i_lock); nfsi->ncommit++; set_bit(PG_NEED_COMMIT, &(req)->wb_flags); radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_COMMIT); - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); __mark_inode_dirty(inode, I_DIRTY_DATASYNC); } @@ -534,10 +534,10 @@ static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, u BUG_ON(!NFS_WBACK_BUSY(req)); kref_get(&req->wb_kref); - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); error = nfs_wait_on_request(req); nfs_release_request(req); - spin_lock(&nfsi->req_lock); + spin_lock(&inode->i_lock); if (error < 0) return error; res++; @@ -602,7 +602,6 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, { struct address_space *mapping = page->mapping; struct inode *inode = mapping->host; - struct nfs_inode *nfsi = NFS_I(inode); struct nfs_page *req, *new = NULL; pgoff_t rqend, end; @@ -612,13 +611,13 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, /* Loop over all inode entries and see if we find * A request for the page we wish to update */ - spin_lock(&nfsi->req_lock); + spin_lock(&inode->i_lock); req = nfs_page_find_request_locked(page); if (req) { if (!nfs_lock_request_dontget(req)) { int error; - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); error = nfs_wait_on_request(req); nfs_release_request(req); if (error < 0) { @@ -628,7 +627,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, } continue; } - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); if (new) nfs_release_request(new); break; @@ -639,14 +638,14 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, nfs_lock_request_dontget(new); error = nfs_inode_add_request(inode, new); if (error) { - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); nfs_unlock_request(new); return ERR_PTR(error); } - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); return new; } - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); new = nfs_create_request(ctx, inode, page, offset, bytes); if (IS_ERR(new)) @@ -974,9 +973,9 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) } if (nfs_write_need_commit(data)) { - spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; + struct inode *inode = page->mapping->host; - spin_lock(req_lock); + spin_lock(&inode->i_lock); if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) { /* Do nothing we need to resend the writes */ } else if (!test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) { @@ -987,7 +986,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) clear_bit(PG_NEED_COMMIT, &req->wb_flags); dprintk(" server reboot detected\n"); } - spin_unlock(req_lock); + spin_unlock(&inode->i_lock); } else dprintk(" OK\n"); @@ -1277,13 +1276,12 @@ static const struct rpc_call_ops nfs_commit_ops = { int nfs_commit_inode(struct inode *inode, int how) { - struct nfs_inode *nfsi = NFS_I(inode); LIST_HEAD(head); int res; - spin_lock(&nfsi->req_lock); + spin_lock(&inode->i_lock); res = nfs_scan_commit(inode, &head, 0, 0); - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); if (res) { int error = nfs_commit_list(inode, &head, how); if (error < 0) @@ -1301,7 +1299,6 @@ static inline int nfs_commit_list(struct inode *inode, struct list_head *head, i long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) { struct inode *inode = mapping->host; - struct nfs_inode *nfsi = NFS_I(inode); pgoff_t idx_start, idx_end; unsigned int npages = 0; LIST_HEAD(head); @@ -1323,7 +1320,7 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr } } how &= ~FLUSH_NOCOMMIT; - spin_lock(&nfsi->req_lock); + spin_lock(&inode->i_lock); do { ret = nfs_wait_on_requests_locked(inode, idx_start, npages); if (ret != 0) @@ -1334,18 +1331,19 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr if (pages == 0) break; if (how & FLUSH_INVALIDATE) { - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); nfs_cancel_commit_list(&head); ret = pages; - spin_lock(&nfsi->req_lock); + spin_lock(&inode->i_lock); continue; } pages += nfs_scan_commit(inode, &head, 0, 0); - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); ret = nfs_commit_list(inode, &head, how); - spin_lock(&nfsi->req_lock); + spin_lock(&inode->i_lock); + } while (ret >= 0); - spin_unlock(&nfsi->req_lock); + spin_unlock(&inode->i_lock); return ret; } @@ -1439,7 +1437,6 @@ int nfs_set_page_dirty(struct page *page) { struct address_space *mapping = page->mapping; struct inode *inode; - spinlock_t *req_lock; struct nfs_page *req; int ret; @@ -1448,18 +1445,17 @@ int nfs_set_page_dirty(struct page *page) inode = mapping->host; if (!inode) goto out_raced; - req_lock = &NFS_I(inode)->req_lock; - spin_lock(req_lock); + spin_lock(&inode->i_lock); req = nfs_page_find_request_locked(page); if (req != NULL) { /* Mark any existing write requests for flushing */ ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags); - spin_unlock(req_lock); + spin_unlock(&inode->i_lock); nfs_release_request(req); return ret; } ret = __set_page_dirty_nobuffers(page); - spin_unlock(req_lock); + spin_unlock(&inode->i_lock); return ret; out_raced: return !TestSetPageDirty(page); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index bf24151d63b..cf395351cdd 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -156,7 +156,6 @@ struct nfs_inode { /* * This is the list of dirty unwritten pages. */ - spinlock_t req_lock; struct radix_tree_root nfs_page_tree; unsigned long ncommit, -- cgit v1.2.3-70-g09d2 From 27b3f949b769a208e2849d28e7ad64cadac5d0e3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 2 Jul 2007 10:24:56 -0400 Subject: NFSv4: Fix a credential reference leak in nfs4_get_state_owner() Signed-off-by: Trond Myklebust --- fs/nfs/nfs4state.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 5d7ffbfc348..0030248d63e 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -83,7 +83,7 @@ nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred) if (!list_empty(&clp->cl_unused)) { sp = list_entry(clp->cl_unused.next, struct nfs4_state_owner, so_list); atomic_inc(&sp->so_count); - sp->so_cred = cred; + sp->so_cred = get_rpccred(cred); list_move(&sp->so_list, &clp->cl_state_owners); clp->cl_nunused--; } @@ -175,7 +175,6 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct struct nfs_client *clp = server->nfs_client; struct nfs4_state_owner *sp, *new; - get_rpccred(cred); new = nfs4_alloc_state_owner(); spin_lock(&clp->cl_lock); sp = nfs4_find_state_owner(clp, cred); @@ -185,7 +184,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct list_add(&new->so_list, &clp->cl_state_owners); new->so_client = clp; new->so_id = nfs4_alloc_lockowner_id(clp); - new->so_cred = cred; + new->so_cred = get_rpccred(cred); sp = new; new = NULL; } @@ -193,7 +192,6 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct kfree(new); if (sp != NULL) return sp; - put_rpccred(cred); return NULL; } -- cgit v1.2.3-70-g09d2 From 7af654f8d1b7460415af5d1d326233478dd0f563 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 2 Jul 2007 12:49:23 -0400 Subject: NFSv4: Don't reuse expired nfs4_state_owner structs That just confuses certain NFSv4 servers. Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 10 ---------- fs/nfs/nfs4state.c | 28 ---------------------------- include/linux/nfs_fs_sb.h | 2 -- 3 files changed, 40 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 71d4c4cdac5..6b424407d63 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -131,7 +131,6 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, init_rwsem(&clp->cl_sem); INIT_LIST_HEAD(&clp->cl_delegations); INIT_LIST_HEAD(&clp->cl_state_owners); - INIT_LIST_HEAD(&clp->cl_unused); spin_lock_init(&clp->cl_lock); INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); @@ -155,15 +154,6 @@ static void nfs4_shutdown_client(struct nfs_client *clp) #ifdef CONFIG_NFS_V4 if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) nfs4_kill_renewd(clp); - while (!list_empty(&clp->cl_unused)) { - struct nfs4_state_owner *sp; - - sp = list_entry(clp->cl_unused.next, - struct nfs4_state_owner, - so_list); - list_del(&sp->so_list); - kfree(sp); - } BUG_ON(!list_empty(&clp->cl_state_owners)); if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) nfs_idmap_delete(clp); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0030248d63e..2b00c45aebe 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -75,21 +75,6 @@ nfs4_alloc_lockowner_id(struct nfs_client *clp) return clp->cl_lockowner_id ++; } -static struct nfs4_state_owner * -nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred) -{ - struct nfs4_state_owner *sp = NULL; - - if (!list_empty(&clp->cl_unused)) { - sp = list_entry(clp->cl_unused.next, struct nfs4_state_owner, so_list); - atomic_inc(&sp->so_count); - sp->so_cred = get_rpccred(cred); - list_move(&sp->so_list, &clp->cl_state_owners); - clp->cl_nunused--; - } - return sp; -} - struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) { struct nfs4_state_owner *sp; @@ -178,8 +163,6 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct new = nfs4_alloc_state_owner(); spin_lock(&clp->cl_lock); sp = nfs4_find_state_owner(clp, cred); - if (sp == NULL) - sp = nfs4_client_grab_unused(clp, cred); if (sp == NULL && new != NULL) { list_add(&new->so_list, &clp->cl_state_owners); new->so_client = clp; @@ -206,17 +189,6 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp) if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) return; - if (clp->cl_nunused >= OPENOWNER_POOL_SIZE) - goto out_free; - if (list_empty(&sp->so_list)) - goto out_free; - list_move(&sp->so_list, &clp->cl_unused); - clp->cl_nunused++; - spin_unlock(&clp->cl_lock); - put_rpccred(cred); - cred = NULL; - return; -out_free: list_del(&sp->so_list); spin_unlock(&clp->cl_lock); put_rpccred(cred); diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 144d955dc46..2cef0a68aa7 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -44,8 +44,6 @@ struct nfs_client { struct list_head cl_delegations; struct list_head cl_state_owners; - struct list_head cl_unused; - int cl_nunused; spinlock_t cl_lock; unsigned long cl_lease_time; -- cgit v1.2.3-70-g09d2 From bd625ba80d84d9de003b8a4bf61fd937b82aca09 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 8 Jul 2007 18:38:23 -0400 Subject: NFSv4: Fix the NFSv4 owner and owner_group size estimates Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 859b1363325..932bc79a902 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -87,9 +87,11 @@ static int nfs4_stat_to_errno(int); #define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) +#define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) +#define nfs4_group_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) /* This is based on getfattr, which uses the most attributes: */ #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ - 3 + 3 + 3 + 2 * nfs4_name_maxsz)) + 3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz)) #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ nfs4_fattr_value_maxsz) #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) -- cgit v1.2.3-70-g09d2 From 2cebf82883f49fd26148da5d9a43d1b4363f1d59 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 2 Jul 2007 13:57:28 -0400 Subject: NFSv4: Fix the underestimate of NFSv4 open request size The maximum size depends on the filename size and a number of other elements which are currently not being counted. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 63 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 18 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 932bc79a902..f6068bf3823 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -70,7 +70,8 @@ static int nfs4_stat_to_errno(int); /* lock,open owner id: * we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT >> 2) */ -#define owner_id_maxsz (1 + 1) +#define open_owner_id_maxsz (1 + 1) +#define lock_owner_id_maxsz (1 + 1) #define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) #define compound_decode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) #define op_encode_hdr_maxsz (1) @@ -120,6 +121,25 @@ static int nfs4_stat_to_errno(int); (op_decode_hdr_maxsz) #define encode_lookup_maxsz (op_encode_hdr_maxsz + \ 1 + ((3 + NFS4_FHSIZE) >> 2)) +#define encode_share_access_maxsz \ + (2) +#define encode_createmode_maxsz (1 + nfs4_fattr_maxsz) +#define encode_opentype_maxsz (1 + encode_createmode_maxsz) +#define encode_claim_null_maxsz (1 + nfs4_name_maxsz) +#define encode_open_maxsz (op_encode_hdr_maxsz + \ + 2 + encode_share_access_maxsz + 2 + \ + open_owner_id_maxsz + \ + encode_opentype_maxsz + \ + encode_claim_null_maxsz) +#define decode_ace_maxsz (3 + nfs4_owner_maxsz) +#define decode_delegation_maxsz (1 + XDR_QUADLEN(NFS4_STATEID_SIZE) + 1 + \ + decode_ace_maxsz) +#define decode_change_info_maxsz (5) +#define decode_open_maxsz (op_decode_hdr_maxsz + \ + XDR_QUADLEN(NFS4_STATEID_SIZE) + \ + decode_change_info_maxsz + 1 + \ + nfs4_fattr_bitmap_maxsz + \ + decode_delegation_maxsz) #define encode_remove_maxsz (op_encode_hdr_maxsz + \ nfs4_name_maxsz) #define encode_rename_maxsz (op_encode_hdr_maxsz + \ @@ -136,7 +156,9 @@ static int nfs4_stat_to_errno(int); #define encode_create_maxsz (op_encode_hdr_maxsz + \ 2 + nfs4_name_maxsz + \ nfs4_fattr_maxsz) -#define decode_create_maxsz (op_decode_hdr_maxsz + 8) +#define decode_create_maxsz (op_decode_hdr_maxsz + \ + decode_change_info_maxsz + \ + nfs4_fattr_bitmap_maxsz) #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ @@ -176,16 +198,21 @@ static int nfs4_stat_to_errno(int); op_decode_hdr_maxsz + 2 + \ decode_getattr_maxsz) #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ - encode_putfh_maxsz + \ - op_encode_hdr_maxsz + \ - 13 + 3 + 2 + 64 + \ - encode_getattr_maxsz + \ - encode_getfh_maxsz) + encode_putfh_maxsz + \ + encode_savefh_maxsz + \ + encode_open_maxsz + \ + encode_getfh_maxsz + \ + encode_getattr_maxsz + \ + encode_restorefh_maxsz + \ + encode_getattr_maxsz) #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ - decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \ - decode_getattr_maxsz + \ - decode_getfh_maxsz) + decode_putfh_maxsz + \ + decode_savefh_maxsz + \ + decode_open_maxsz + \ + decode_getfh_maxsz + \ + decode_getattr_maxsz + \ + decode_restorefh_maxsz + \ + decode_getattr_maxsz) #define NFS4_enc_open_confirm_sz \ (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ @@ -195,12 +222,12 @@ static int nfs4_stat_to_errno(int); op_decode_hdr_maxsz + 4) #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + \ - 11) + encode_open_maxsz + \ + encode_getattr_maxsz) #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + \ - 4 + 5 + 2 + 3) + decode_open_maxsz + \ + decode_getattr_maxsz) #define NFS4_enc_open_downgrade_sz \ (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ @@ -258,19 +285,19 @@ static int nfs4_stat_to_errno(int); op_encode_hdr_maxsz + \ 1 + 1 + 2 + 2 + \ 1 + 4 + 1 + 2 + \ - owner_id_maxsz) + lock_owner_id_maxsz) #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_getattr_maxsz + \ op_decode_hdr_maxsz + \ 2 + 2 + 1 + 2 + \ - owner_id_maxsz) + lock_owner_id_maxsz) #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_getattr_maxsz + \ op_encode_hdr_maxsz + \ 1 + 2 + 2 + 2 + \ - owner_id_maxsz) + lock_owner_id_maxsz) #define NFS4_dec_lockt_sz (NFS4_dec_lock_sz) #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ -- cgit v1.2.3-70-g09d2 From e6889620e89525ebf41f0eed937edb3dc065cf1d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 2 Jul 2007 13:58:30 -0400 Subject: NFSv4: Fix underestimate of NFSv4 lookup request size Also fix up the underestimate of fs_locations Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index f6068bf3823..4c8f67d4752 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -119,8 +119,8 @@ static int nfs4_stat_to_errno(int); 3 + (NFS4_VERIFIER_SIZE >> 2)) #define decode_setclientid_confirm_maxsz \ (op_decode_hdr_maxsz) -#define encode_lookup_maxsz (op_encode_hdr_maxsz + \ - 1 + ((3 + NFS4_FHSIZE) >> 2)) +#define encode_lookup_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz) +#define decode_lookup_maxsz (op_decode_hdr_maxsz) #define encode_share_access_maxsz \ (2) #define encode_createmode_maxsz (1 + nfs4_fattr_maxsz) @@ -161,6 +161,10 @@ static int nfs4_stat_to_errno(int); nfs4_fattr_bitmap_maxsz) #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) +#define encode_fs_locations_maxsz \ + (encode_getattr_maxsz) +#define decode_fs_locations_maxsz \ + (0) #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ @@ -327,7 +331,7 @@ static int nfs4_stat_to_errno(int); encode_getfh_maxsz) #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + \ + decode_lookup_maxsz + \ decode_getattr_maxsz + \ decode_getfh_maxsz) #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ @@ -446,12 +450,13 @@ static int nfs4_stat_to_errno(int); #define NFS4_enc_fs_locations_sz \ (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_getattr_maxsz) + encode_lookup_maxsz + \ + encode_fs_locations_maxsz) #define NFS4_dec_fs_locations_sz \ (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + \ - nfs4_fattr_bitmap_maxsz) + decode_lookup_maxsz + \ + decode_fs_locations_maxsz) static struct { unsigned int mode; -- cgit v1.2.3-70-g09d2 From 88d9093997e1c73ca98db41b5605dbde7783845f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 2 Jul 2007 14:03:03 -0400 Subject: NFSv4: nfs_increment_open_seqid should not return a value It is a void function... Signed-off-by: Trond Myklebust --- fs/nfs/nfs4state.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 2b00c45aebe..0f79d56e97f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -528,7 +528,7 @@ void nfs_free_seqid(struct nfs_seqid *seqid) * failed with a seqid incrementing error - * see comments nfs_fs.h:seqid_mutating_error() */ -static inline void nfs_increment_seqid(int status, struct nfs_seqid *seqid) +static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) { switch (status) { case 0: @@ -557,7 +557,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) struct nfs4_state_owner, so_seqid); nfs4_drop_state_owner(sp); } - return nfs_increment_seqid(status, seqid); + nfs_increment_seqid(status, seqid); } /* @@ -567,7 +567,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) */ void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid) { - return nfs_increment_seqid(status, seqid); + nfs_increment_seqid(status, seqid); } int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) -- cgit v1.2.3-70-g09d2 From 9f958ab8858c75df800e0121b1920182820cbc39 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 2 Jul 2007 13:58:33 -0400 Subject: NFSv4: Reduce the chances of an open_owner identifier collision Currently we just use a 32-bit counter. Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 3 +- fs/nfs/nfs4_fs.h | 17 ++-- fs/nfs/nfs4proc.c | 8 +- fs/nfs/nfs4state.c | 193 ++++++++++++++++++++++++++++++++++++---------- fs/nfs/nfs4xdr.c | 27 ++++--- include/linux/nfs_fs_sb.h | 5 +- include/linux/nfs_xdr.h | 4 +- 7 files changed, 190 insertions(+), 67 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 6b424407d63..ccb455053ee 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -130,7 +130,6 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, #ifdef CONFIG_NFS_V4 init_rwsem(&clp->cl_sem); INIT_LIST_HEAD(&clp->cl_delegations); - INIT_LIST_HEAD(&clp->cl_state_owners); spin_lock_init(&clp->cl_lock); INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); @@ -154,7 +153,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) #ifdef CONFIG_NFS_V4 if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) nfs4_kill_renewd(clp); - BUG_ON(!list_empty(&clp->cl_state_owners)); + BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) nfs_idmap_delete(clp); #endif diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c97a0ad8430..44b56c915f7 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -70,19 +70,25 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status seqid->flags |= NFS_SEQID_CONFIRMED; } +struct nfs_unique_id { + struct rb_node rb_node; + __u64 id; +}; + /* * NFS4 state_owners and lock_owners are simply labels for ordered * sequences of RPC calls. Their sole purpose is to provide once-only * semantics by allowing the server to identify replayed requests. */ struct nfs4_state_owner { - spinlock_t so_lock; - struct list_head so_list; /* per-clientid list of state_owners */ + struct nfs_unique_id so_owner_id; struct nfs_client *so_client; - u32 so_id; /* 32-bit identifier, unique */ - atomic_t so_count; + struct rb_node so_client_node; struct rpc_cred *so_cred; /* Associated cred */ + + spinlock_t so_lock; + atomic_t so_count; struct list_head so_states; struct list_head so_delegations; struct nfs_seqid_counter so_seqid; @@ -108,7 +114,7 @@ struct nfs4_lock_state { #define NFS_LOCK_INITIALIZED 1 int ls_flags; struct nfs_seqid_counter ls_seqid; - u32 ls_id; + struct nfs_unique_id ls_id; nfs4_stateid ls_stateid; atomic_t ls_count; }; @@ -189,7 +195,6 @@ extern void nfs4_renew_state(struct work_struct *); /* nfs4state.c */ struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); -extern u32 nfs4_alloc_lockowner_id(struct nfs_client *); extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); extern void nfs4_put_state_owner(struct nfs4_state_owner *); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 84d0b7e0dd6..1840ebc78fd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -253,7 +253,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, p->o_arg.fh = NFS_FH(dir); p->o_arg.open_flags = flags, p->o_arg.clientid = server->nfs_client->cl_clientid; - p->o_arg.id = sp->so_id; + p->o_arg.id = sp->so_owner_id.id; p->o_arg.name = &p->path.dentry->d_name; p->o_arg.server = server; p->o_arg.bitmask = server->attr_bitmask; @@ -651,7 +651,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) return; /* Update sequence id. */ - data->o_arg.id = sp->so_id; + data->o_arg.id = sp->so_owner_id.id; data->o_arg.clientid = sp->so_client->cl_clientid; if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; @@ -3029,7 +3029,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock if (status != 0) goto out; lsp = request->fl_u.nfs4_fl.owner; - arg.lock_owner.id = lsp->ls_id; + arg.lock_owner.id = lsp->ls_id.id; status = rpc_call_sync(server->client, &msg, 0); switch (status) { case 0: @@ -3243,7 +3243,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, goto out_free; p->arg.lock_stateid = &lsp->ls_stateid; p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; - p->arg.lock_owner.id = lsp->ls_id; + p->arg.lock_owner.id = lsp->ls_id.id; p->lsp = lsp; atomic_inc(&lsp->ls_count); p->ctx = get_nfs_open_context(ctx); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0f79d56e97f..ab0b5ab60e6 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -69,18 +70,14 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) return status; } -u32 -nfs4_alloc_lockowner_id(struct nfs_client *clp) -{ - return clp->cl_lockowner_id ++; -} - struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) { struct nfs4_state_owner *sp; + struct rb_node *pos; struct rpc_cred *cred = NULL; - list_for_each_entry(sp, &clp->cl_state_owners, so_list) { + for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { + sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); if (list_empty(&sp->so_states)) continue; cred = get_rpccred(sp->so_cred); @@ -92,32 +89,129 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) { struct nfs4_state_owner *sp; + struct rb_node *pos; - if (!list_empty(&clp->cl_state_owners)) { - sp = list_entry(clp->cl_state_owners.next, - struct nfs4_state_owner, so_list); + pos = rb_first(&clp->cl_state_owners); + if (pos != NULL) { + sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); return get_rpccred(sp->so_cred); } return NULL; } +static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new, + __u64 minval, int maxbits) +{ + struct rb_node **p, *parent; + struct nfs_unique_id *pos; + __u64 mask = ~0ULL; + + if (maxbits < 64) + mask = (1ULL << maxbits) - 1ULL; + + /* Ensure distribution is more or less flat */ + get_random_bytes(&new->id, sizeof(new->id)); + new->id &= mask; + if (new->id < minval) + new->id += minval; +retry: + p = &root->rb_node; + parent = NULL; + + while (*p != NULL) { + parent = *p; + pos = rb_entry(parent, struct nfs_unique_id, rb_node); + + if (new->id < pos->id) + p = &(*p)->rb_left; + else if (new->id > pos->id) + p = &(*p)->rb_right; + else + goto id_exists; + } + rb_link_node(&new->rb_node, parent, p); + rb_insert_color(&new->rb_node, root); + return; +id_exists: + for (;;) { + new->id++; + if (new->id < minval || (new->id & mask) != new->id) { + new->id = minval; + break; + } + parent = rb_next(parent); + if (parent == NULL) + break; + pos = rb_entry(parent, struct nfs_unique_id, rb_node); + if (new->id < pos->id) + break; + } + goto retry; +} + +static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id) +{ + rb_erase(&id->rb_node, root); +} + static struct nfs4_state_owner * nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred) { + struct rb_node **p = &clp->cl_state_owners.rb_node, + *parent = NULL; struct nfs4_state_owner *sp, *res = NULL; - list_for_each_entry(sp, &clp->cl_state_owners, so_list) { - if (sp->so_cred != cred) - continue; - atomic_inc(&sp->so_count); - /* Move to the head of the list */ - list_move(&sp->so_list, &clp->cl_state_owners); - res = sp; - break; + while (*p != NULL) { + parent = *p; + sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); + + if (cred < sp->so_cred) + p = &parent->rb_left; + else if (cred > sp->so_cred) + p = &parent->rb_right; + else { + atomic_inc(&sp->so_count); + res = sp; + break; + } } return res; } +static struct nfs4_state_owner * +nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new) +{ + struct rb_node **p = &clp->cl_state_owners.rb_node, + *parent = NULL; + struct nfs4_state_owner *sp; + + while (*p != NULL) { + parent = *p; + sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); + + if (new->so_cred < sp->so_cred) + p = &parent->rb_left; + else if (new->so_cred > sp->so_cred) + p = &parent->rb_right; + else { + atomic_inc(&sp->so_count); + return sp; + } + } + nfs_alloc_unique_id(&clp->cl_openowner_id, &new->so_owner_id, 1, 64); + rb_link_node(&new->so_client_node, parent, p); + rb_insert_color(&new->so_client_node, &clp->cl_state_owners); + return new; +} + +static void +nfs4_remove_state_owner(struct nfs_client *clp, struct nfs4_state_owner *sp) +{ + if (!RB_EMPTY_NODE(&sp->so_client_node)) + rb_erase(&sp->so_client_node, &clp->cl_state_owners); + nfs_free_unique_id(&clp->cl_openowner_id, &sp->so_owner_id); +} + /* * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to * create a new state_owner. @@ -145,10 +239,14 @@ nfs4_alloc_state_owner(void) void nfs4_drop_state_owner(struct nfs4_state_owner *sp) { - struct nfs_client *clp = sp->so_client; - spin_lock(&clp->cl_lock); - list_del_init(&sp->so_list); - spin_unlock(&clp->cl_lock); + if (!RB_EMPTY_NODE(&sp->so_client_node)) { + struct nfs_client *clp = sp->so_client; + + spin_lock(&clp->cl_lock); + rb_erase(&sp->so_client_node, &clp->cl_state_owners); + RB_CLEAR_NODE(&sp->so_client_node); + spin_unlock(&clp->cl_lock); + } } /* @@ -160,22 +258,24 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct struct nfs_client *clp = server->nfs_client; struct nfs4_state_owner *sp, *new; - new = nfs4_alloc_state_owner(); spin_lock(&clp->cl_lock); sp = nfs4_find_state_owner(clp, cred); - if (sp == NULL && new != NULL) { - list_add(&new->so_list, &clp->cl_state_owners); - new->so_client = clp; - new->so_id = nfs4_alloc_lockowner_id(clp); - new->so_cred = get_rpccred(cred); - sp = new; - new = NULL; - } spin_unlock(&clp->cl_lock); - kfree(new); if (sp != NULL) return sp; - return NULL; + new = nfs4_alloc_state_owner(); + if (new == NULL) + return NULL; + new->so_client = clp; + new->so_cred = cred; + spin_lock(&clp->cl_lock); + sp = nfs4_insert_state_owner(clp, new); + spin_unlock(&clp->cl_lock); + if (sp == new) + get_rpccred(cred); + else + kfree(new); + return sp; } /* @@ -189,7 +289,7 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp) if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) return; - list_del(&sp->so_list); + nfs4_remove_state_owner(clp, sp); spin_unlock(&clp->cl_lock); put_rpccred(cred); kfree(sp); @@ -386,12 +486,22 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f atomic_set(&lsp->ls_count, 1); lsp->ls_owner = fl_owner; spin_lock(&clp->cl_lock); - lsp->ls_id = nfs4_alloc_lockowner_id(clp); + nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); spin_unlock(&clp->cl_lock); INIT_LIST_HEAD(&lsp->ls_locks); return lsp; } +static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) +{ + struct nfs_client *clp = lsp->ls_state->owner->so_client; + + spin_lock(&clp->cl_lock); + nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); + spin_unlock(&clp->cl_lock); + kfree(lsp); +} + /* * Return a compatible lock_state. If no initialized lock_state structure * exists, return an uninitialized one. @@ -421,7 +531,8 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ return NULL; } spin_unlock(&state->state_lock); - kfree(new); + if (new != NULL) + nfs4_free_lock_state(new); return lsp; } @@ -442,7 +553,7 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) if (list_empty(&state->lock_states)) clear_bit(LK_STATE_IN_USE, &state->flags); spin_unlock(&state->state_lock); - kfree(lsp); + nfs4_free_lock_state(lsp); } static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) @@ -719,11 +830,13 @@ out_err: static void nfs4_state_mark_reclaim(struct nfs_client *clp) { struct nfs4_state_owner *sp; + struct rb_node *pos; struct nfs4_state *state; struct nfs4_lock_state *lock; /* Reset all sequence ids to zero */ - list_for_each_entry(sp, &clp->cl_state_owners, so_list) { + for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { + sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); sp->so_seqid.counter = 0; sp->so_seqid.flags = 0; spin_lock(&sp->so_lock); @@ -742,6 +855,7 @@ static int reclaimer(void *ptr) { struct nfs_client *clp = ptr; struct nfs4_state_owner *sp; + struct rb_node *pos; struct nfs4_state_recovery_ops *ops; struct rpc_cred *cred; int status = 0; @@ -787,7 +901,8 @@ restart_loop: /* Mark all delegations for reclaim */ nfs_delegation_mark_reclaim(clp); /* Note: list is protected by exclusive lock on cl->cl_sem */ - list_for_each_entry(sp, &clp->cl_state_owners, so_list) { + for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { + sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); status = nfs4_reclaim_open_state(ops, sp); if (status < 0) { if (status == -NFS4ERR_NO_GRACE) { diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 4c8f67d4752..c08738441f7 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -68,10 +68,10 @@ static int nfs4_stat_to_errno(int); #endif /* lock,open owner id: - * we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT >> 2) + * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2) */ -#define open_owner_id_maxsz (1 + 1) -#define lock_owner_id_maxsz (1 + 1) +#define open_owner_id_maxsz (1 + 4) +#define lock_owner_id_maxsz (1 + 4) #define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) #define compound_decode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) #define op_encode_hdr_maxsz (1) @@ -827,13 +827,14 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args) WRITE64(nfs4_lock_length(args->fl)); WRITE32(args->new_lock_owner); if (args->new_lock_owner){ - RESERVE_SPACE(4+NFS4_STATEID_SIZE+20); + RESERVE_SPACE(4+NFS4_STATEID_SIZE+32); WRITE32(args->open_seqid->sequence->counter); WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE); WRITE32(args->lock_seqid->sequence->counter); WRITE64(args->lock_owner.clientid); - WRITE32(4); - WRITE32(args->lock_owner.id); + WRITE32(16); + WRITEMEM("lock id:", 8); + WRITE64(args->lock_owner.id); } else { RESERVE_SPACE(NFS4_STATEID_SIZE+4); @@ -848,14 +849,15 @@ static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *arg { __be32 *p; - RESERVE_SPACE(40); + RESERVE_SPACE(52); WRITE32(OP_LOCKT); WRITE32(nfs4_lock_type(args->fl, 0)); WRITE64(args->fl->fl_start); WRITE64(nfs4_lock_length(args->fl)); WRITE64(args->lock_owner.clientid); - WRITE32(4); - WRITE32(args->lock_owner.id); + WRITE32(16); + WRITEMEM("lock id:", 8); + WRITE64(args->lock_owner.id); return 0; } @@ -920,10 +922,11 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena WRITE32(OP_OPEN); WRITE32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->open_flags); - RESERVE_SPACE(16); + RESERVE_SPACE(28); WRITE64(arg->clientid); - WRITE32(4); - WRITE32(arg->id); + WRITE32(16); + WRITEMEM("open id:", 8); + WRITE64(arg->id); } static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 2cef0a68aa7..0cac49bc095 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -34,7 +34,8 @@ struct nfs_client { nfs4_verifier cl_confirm; unsigned long cl_state; - u32 cl_lockowner_id; + struct rb_root cl_openowner_id; + struct rb_root cl_lockowner_id; /* * The following rwsem ensures exclusive access to the server @@ -43,7 +44,7 @@ struct nfs_client { struct rw_semaphore cl_sem; struct list_head cl_delegations; - struct list_head cl_state_owners; + struct rb_root cl_state_owners; spinlock_t cl_lock; unsigned long cl_lease_time; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index f7100df3a69..38d77681cf2 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -119,7 +119,7 @@ struct nfs_openargs { struct nfs_seqid * seqid; int open_flags; __u64 clientid; - __u32 id; + __u64 id; union { struct iattr * attrs; /* UNCHECKED, GUARDED */ nfs4_verifier verifier; /* EXCLUSIVE */ @@ -181,7 +181,7 @@ struct nfs_closeres { * */ struct nfs_lowner { __u64 clientid; - u32 id; + __u64 id; }; struct nfs_lock_args { -- cgit v1.2.3-70-g09d2 From 1b45c46cf75d9c48eb611d5cc41607ac1f046606 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 3 Jul 2007 13:04:56 -0400 Subject: NFSv4: Fix atomic open for execute... Currently we do not check for the FMODE_EXEC flag as we should. For that particular case, we need to perform an ACCESS call to the server in order to check that the file is executable. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1840ebc78fd..69aab8db494 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -769,6 +769,8 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf mask |= MAY_READ; if (openflags & FMODE_WRITE) mask |= MAY_WRITE; + if (openflags & FMODE_EXEC) + mask |= MAY_EXEC; status = nfs_access_get_cached(inode, cred, &cache); if (status == 0) goto out; @@ -1269,7 +1271,16 @@ out: static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state) { struct file *filp; + int ret; + /* If the open_intent is for execute, we have an extra check to make */ + if (nd->intent.open.flags & FMODE_EXEC) { + ret = _nfs4_do_access(state->inode, + state->owner->so_cred, + nd->intent.open.flags); + if (ret < 0) + goto out_close; + } filp = lookup_instantiate_filp(nd, path->dentry, NULL); if (!IS_ERR(filp)) { struct nfs_open_context *ctx; @@ -1277,8 +1288,10 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct ctx->state = state; return 0; } + ret = PTR_ERR(filp); +out_close: nfs4_close_state(path, state, nd->intent.open.flags); - return PTR_ERR(filp); + return ret; } struct dentry * -- cgit v1.2.3-70-g09d2 From 1c816efa245111c52858fbe55d99474f3c149dd3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 3 Jul 2007 14:41:19 -0400 Subject: NFSv4: Fix a bug in __nfs4_find_state_byowner The test for state->state == 0 does not tell you that the stateid is in the process of being freed. It really tells you that the stateid is not yet initialised... Signed-off-by: Trond Myklebust --- fs/nfs/nfs4state.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index ab0b5ab60e6..ac816b303f3 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -333,13 +333,10 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner) struct nfs4_state *state; list_for_each_entry(state, &nfsi->open_states, inode_states) { - /* Is this in the process of being freed? */ - if (state->state == 0) + if (state->owner != owner) continue; - if (state->owner == owner) { - atomic_inc(&state->count); + if (atomic_inc_not_zero(&state->count)) return state; - } } return NULL; } -- cgit v1.2.3-70-g09d2 From 549d6ed5e85003370fe858e70864a71882491d28 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 3 Jul 2007 16:42:45 -0400 Subject: NFSv4: set the delegation in nfs4_opendata_to_nfs4_state This ensures that nfs4_open_release() and nfs4_open_confirm_release() can now handle an eventual delegation that was returned with out open. As such, it fixes a delegation "leak" when the user breaks out of an open call. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 69aab8db494..4f0b06d549f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -356,6 +356,21 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data if (state == NULL) goto put_inode; update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags); + if (data->o_res.delegation_type != 0) { + struct nfs_inode *nfsi = NFS_I(inode); + int delegation_flags = 0; + + if (nfsi->delegation) + delegation_flags = nfsi->delegation->flags; + if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) + nfs_inode_set_delegation(state->inode, + data->owner->so_cred, + &data->o_res); + else + nfs_inode_reclaim_delegation(state->inode, + data->owner->so_cred, + &data->o_res); + } put_inode: iput(inode); out: @@ -433,23 +448,8 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * opendata->o_res.delegation_type = delegation; opendata->o_arg.open_flags |= mode; newstate = nfs4_opendata_to_nfs4_state(opendata); - if (newstate != NULL) { - if (opendata->o_res.delegation_type != 0) { - struct nfs_inode *nfsi = NFS_I(newstate->inode); - int delegation_flags = 0; - if (nfsi->delegation) - delegation_flags = nfsi->delegation->flags; - if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) - nfs_inode_set_delegation(newstate->inode, - opendata->owner->so_cred, - &opendata->o_res); - else - nfs_inode_reclaim_delegation(newstate->inode, - opendata->owner->so_cred, - &opendata->o_res); - } + if (newstate != NULL) nfs4_close_state(&opendata->path, newstate, opendata->o_arg.open_flags); - } if (newstate != state) return -ESTALE; return 0; @@ -1005,8 +1005,6 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct state = nfs4_opendata_to_nfs4_state(opendata); if (state == NULL) goto err_opendata_put; - if (opendata->o_res.delegation_type != 0) - nfs_inode_set_delegation(state->inode, cred, &opendata->o_res); nfs4_opendata_put(opendata); nfs4_put_state_owner(sp); up_read(&clp->cl_sem); -- cgit v1.2.3-70-g09d2 From 2ced46c27058710a6d731d6eca77f1dd14ccde75 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 3 Jul 2007 23:48:13 -0400 Subject: NFSv4: Fix up a bug in nfs4_open_recover() Don't clobber the delegation info... Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 65 ++++++++++++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4f0b06d549f..03b60c67ca7 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -230,6 +230,16 @@ struct nfs4_opendata { int cancelled; }; + +static void nfs4_init_opendata_res(struct nfs4_opendata *p) +{ + p->o_res.f_attr = &p->f_attr; + p->o_res.dir_attr = &p->dir_attr; + p->o_res.server = p->o_arg.server; + nfs_fattr_init(&p->f_attr); + nfs_fattr_init(&p->dir_attr); +} + static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, struct nfs4_state_owner *sp, int flags, const struct iattr *attrs) @@ -258,11 +268,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, p->o_arg.server = server; p->o_arg.bitmask = server->attr_bitmask; p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; - p->o_res.f_attr = &p->f_attr; - p->o_res.dir_attr = &p->dir_attr; - p->o_res.server = server; - nfs_fattr_init(&p->f_attr); - nfs_fattr_init(&p->dir_attr); if (flags & O_EXCL) { u32 *s = (u32 *) p->o_arg.u.verifier.data; s[0] = jiffies; @@ -274,6 +279,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, p->c_arg.fh = &p->o_res.fh; p->c_arg.stateid = &p->o_res.stateid; p->c_arg.seqid = p->o_arg.seqid; + nfs4_init_opendata_res(p); kref_init(&p->kref); return p; err_free: @@ -394,64 +400,54 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state * return ERR_PTR(-ENOENT); } -static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid) +static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) { + struct nfs4_state *newstate; int ret; opendata->o_arg.open_flags = openflags; + memset(&opendata->o_res, 0, sizeof(opendata->o_res)); + memset(&opendata->c_res, 0, sizeof(opendata->c_res)); + nfs4_init_opendata_res(opendata); ret = _nfs4_proc_open(opendata); if (ret != 0) return ret; - memcpy(stateid->data, opendata->o_res.stateid.data, - sizeof(stateid->data)); + newstate = nfs4_opendata_to_nfs4_state(opendata); + if (newstate != NULL) + nfs4_close_state(&opendata->path, newstate, openflags); + *res = newstate; return 0; } static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) { - nfs4_stateid stateid; struct nfs4_state *newstate; - int mode = 0; - int delegation = 0; int ret; /* memory barrier prior to reading state->n_* */ + clear_bit(NFS_DELEGATED_STATE, &state->flags); smp_rmb(); if (state->n_rdwr != 0) { - ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid); + ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); if (ret != 0) return ret; - mode |= FMODE_READ|FMODE_WRITE; - if (opendata->o_res.delegation_type != 0) - delegation = opendata->o_res.delegation_type; - smp_rmb(); + if (newstate != state) + return -ESTALE; } if (state->n_wronly != 0) { - ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid); + ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); if (ret != 0) return ret; - mode |= FMODE_WRITE; - if (opendata->o_res.delegation_type != 0) - delegation = opendata->o_res.delegation_type; - smp_rmb(); + if (newstate != state) + return -ESTALE; } if (state->n_rdonly != 0) { - ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid); + ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); if (ret != 0) return ret; - mode |= FMODE_READ; + if (newstate != state) + return -ESTALE; } - clear_bit(NFS_DELEGATED_STATE, &state->flags); - if (mode == 0) - return 0; - if (opendata->o_res.delegation_type == 0) - opendata->o_res.delegation_type = delegation; - opendata->o_arg.open_flags |= mode; - newstate = nfs4_opendata_to_nfs4_state(opendata); - if (newstate != NULL) - nfs4_close_state(&opendata->path, newstate, opendata->o_arg.open_flags); - if (newstate != state) - return -ESTALE; return 0; } @@ -730,6 +726,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) * want to ensure that it takes the 'error' code path. */ data->rpc_status = -ENOMEM; + data->cancelled = 0; task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); if (IS_ERR(task)) return PTR_ERR(task); -- cgit v1.2.3-70-g09d2 From 901630278469c0d7610554227f39ed2d02d0d270 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 5 Jul 2007 14:55:18 -0400 Subject: NFSv4: Support recalling delegations by stateid There appear to be some rogue servers out there that issue multiple delegations with different stateids for the same file. Ensure that when we return delegations, we do so on a per-stateid basis rather than a per-file basis. Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 80 +++++++++++++++++++++++++++++++++-------------------- fs/nfs/delegation.h | 10 +------ 2 files changed, 51 insertions(+), 39 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 9f17b91205c..cee2ba42b68 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -57,7 +57,7 @@ out_err: return status; } -static void nfs_delegation_claim_opens(struct inode *inode) +static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid) { struct nfs_inode *nfsi = NFS_I(inode); struct nfs_open_context *ctx; @@ -72,6 +72,8 @@ again: continue; if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) continue; + if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0) + continue; get_nfs_open_context(ctx); spin_unlock(&inode->i_lock); err = nfs4_open_delegation_recall(ctx, state); @@ -170,33 +172,55 @@ static void nfs_msync_inode(struct inode *inode) /* * Basic procedure for returning a delegation to the server */ -int __nfs_inode_return_delegation(struct inode *inode) +static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) { struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_inode *nfsi = NFS_I(inode); - struct nfs_delegation *delegation; - int res = 0; nfs_msync_inode(inode); down_read(&clp->cl_sem); /* Guard against new delegated open calls */ down_write(&nfsi->rwsem); - spin_lock(&clp->cl_lock); - delegation = nfsi->delegation; - if (delegation != NULL) { - list_del_init(&delegation->super_list); - nfsi->delegation = NULL; - nfsi->delegation_state = 0; - } - spin_unlock(&clp->cl_lock); - nfs_delegation_claim_opens(inode); + nfs_delegation_claim_opens(inode, &delegation->stateid); up_write(&nfsi->rwsem); up_read(&clp->cl_sem); nfs_msync_inode(inode); - if (delegation != NULL) - res = nfs_do_return_delegation(inode, delegation); - return res; + return nfs_do_return_delegation(inode, delegation); +} + +static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) +{ + struct nfs_delegation *delegation = nfsi->delegation; + + if (delegation == NULL) + goto nomatch; + if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, + sizeof(delegation->stateid.data)) != 0) + goto nomatch; + list_del_init(&delegation->super_list); + nfsi->delegation = NULL; + nfsi->delegation_state = 0; + return delegation; +nomatch: + return NULL; +} + +int nfs_inode_return_delegation(struct inode *inode) +{ + struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; + struct nfs_inode *nfsi = NFS_I(inode); + struct nfs_delegation *delegation; + int err = 0; + + if (nfsi->delegation_state != 0) { + spin_lock(&clp->cl_lock); + delegation = nfs_detach_delegation_locked(nfsi, NULL); + spin_unlock(&clp->cl_lock); + if (delegation != NULL) + err = __nfs_inode_return_delegation(inode, delegation); + } + return err; } /* @@ -218,8 +242,9 @@ restart: inode = igrab(delegation->inode); if (inode == NULL) continue; + nfs_detach_delegation_locked(NFS_I(inode), NULL); spin_unlock(&clp->cl_lock); - nfs_inode_return_delegation(inode); + __nfs_inode_return_delegation(inode, delegation); iput(inode); goto restart; } @@ -243,8 +268,9 @@ restart: inode = igrab(delegation->inode); if (inode == NULL) continue; + nfs_detach_delegation_locked(NFS_I(inode), NULL); spin_unlock(&clp->cl_lock); - nfs_inode_return_delegation(inode); + __nfs_inode_return_delegation(inode, delegation); iput(inode); goto restart; } @@ -285,8 +311,9 @@ restart: inode = igrab(delegation->inode); if (inode == NULL) continue; + nfs_detach_delegation_locked(NFS_I(inode), NULL); spin_unlock(&clp->cl_lock); - nfs_inode_return_delegation(inode); + __nfs_inode_return_delegation(inode, delegation); iput(inode); goto restart; } @@ -316,21 +343,14 @@ static int recall_thread(void *data) down_read(&clp->cl_sem); down_write(&nfsi->rwsem); spin_lock(&clp->cl_lock); - delegation = nfsi->delegation; - if (delegation != NULL && memcmp(delegation->stateid.data, - args->stateid->data, - sizeof(delegation->stateid.data)) == 0) { - list_del_init(&delegation->super_list); - nfsi->delegation = NULL; - nfsi->delegation_state = 0; + delegation = nfs_detach_delegation_locked(nfsi, args->stateid); + if (delegation != NULL) args->result = 0; - } else { - delegation = NULL; + else args->result = -ENOENT; - } spin_unlock(&clp->cl_lock); complete(&args->started); - nfs_delegation_claim_opens(inode); + nfs_delegation_claim_opens(inode, args->stateid); up_write(&nfsi->rwsem); up_read(&clp->cl_sem); nfs_msync_inode(inode); diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index f6e42fb21af..7b22f174244 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -26,7 +26,7 @@ struct nfs_delegation { int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); -int __nfs_inode_return_delegation(struct inode *inode); +int nfs_inode_return_delegation(struct inode *inode); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); @@ -52,14 +52,6 @@ static inline int nfs_have_delegation(struct inode *inode, int flags) return 0; } -static inline int nfs_inode_return_delegation(struct inode *inode) -{ - int err = 0; - - if (NFS_I(inode)->delegation != NULL) - err = __nfs_inode_return_delegation(inode); - return err; -} #else static inline int nfs_have_delegation(struct inode *inode, int flags) { -- cgit v1.2.3-70-g09d2 From 13437e12fb43cb7e285ff59248f781c91578eafe Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 6 Jul 2007 15:10:43 -0400 Subject: NFSv4: Support recalling delegations by stateid part 2 Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 2 +- fs/nfs/delegation.h | 2 +- fs/nfs/nfs4proc.c | 10 ++++------ 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index cee2ba42b68..93a9f4bd9bd 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -76,7 +76,7 @@ again: continue; get_nfs_open_context(ctx); spin_unlock(&inode->i_lock); - err = nfs4_open_delegation_recall(ctx, state); + err = nfs4_open_delegation_recall(ctx, state, stateid); if (err >= 0) err = nfs_delegation_claim_locks(ctx, state); put_nfs_open_context(ctx); diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 7b22f174244..8f79a313516 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -39,7 +39,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp); /* NFSv4 delegation-related procedures */ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); -int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state); +int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 03b60c67ca7..10946415de7 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -510,32 +510,30 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta return ret; } -static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state) +static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) { struct nfs4_state_owner *sp = state->owner; struct nfs4_opendata *opendata; int ret; - if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) - return 0; opendata = nfs4_opendata_alloc(&ctx->path, sp, 0, NULL); if (opendata == NULL) return -ENOMEM; opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; - memcpy(opendata->o_arg.u.delegation.data, state->stateid.data, + memcpy(opendata->o_arg.u.delegation.data, stateid->data, sizeof(opendata->o_arg.u.delegation.data)); ret = nfs4_open_recover(opendata, state); nfs4_opendata_put(opendata); return ret; } -int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state) +int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) { struct nfs4_exception exception = { }; struct nfs_server *server = NFS_SERVER(state->inode); int err; do { - err = _nfs4_open_delegation_recall(ctx, state); + err = _nfs4_open_delegation_recall(ctx, state, stateid); switch (err) { case 0: return err; -- cgit v1.2.3-70-g09d2 From 8383e4602c89857ef926f29ca61ac0a83a614443 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 6 Jul 2007 15:12:04 -0400 Subject: NFSv4: Use RCU to protect delegations Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 114 +++++++++++++++++++++++++++++----------------------- fs/nfs/delegation.h | 14 +++++-- 2 files changed, 73 insertions(+), 55 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 93a9f4bd9bd..56f4f6a99d4 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -27,6 +27,13 @@ static void nfs_free_delegation(struct nfs_delegation *delegation) kfree(delegation); } +static void nfs_free_delegation_callback(struct rcu_head *head) +{ + struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu); + + nfs_free_delegation(delegation); +} + static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) { struct inode *inode = state->inode; @@ -133,10 +140,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct delegation->inode = inode; spin_lock(&clp->cl_lock); - if (nfsi->delegation == NULL) { - list_add(&delegation->super_list, &clp->cl_delegations); - nfsi->delegation = delegation; + if (rcu_dereference(nfsi->delegation) == NULL) { + list_add_rcu(&delegation->super_list, &clp->cl_delegations); nfsi->delegation_state = delegation->type; + rcu_assign_pointer(nfsi->delegation, delegation); delegation = NULL; } else { if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, @@ -157,7 +164,7 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * int res = 0; res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); - nfs_free_delegation(delegation); + call_rcu(&delegation->rcu, nfs_free_delegation_callback); return res; } @@ -191,16 +198,16 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) { - struct nfs_delegation *delegation = nfsi->delegation; + struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); if (delegation == NULL) goto nomatch; if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, sizeof(delegation->stateid.data)) != 0) goto nomatch; - list_del_init(&delegation->super_list); - nfsi->delegation = NULL; + list_del_rcu(&delegation->super_list); nfsi->delegation_state = 0; + rcu_assign_pointer(nfsi->delegation, NULL); return delegation; nomatch: return NULL; @@ -213,7 +220,7 @@ int nfs_inode_return_delegation(struct inode *inode) struct nfs_delegation *delegation; int err = 0; - if (nfsi->delegation_state != 0) { + if (rcu_dereference(nfsi->delegation) != NULL) { spin_lock(&clp->cl_lock); delegation = nfs_detach_delegation_locked(nfsi, NULL); spin_unlock(&clp->cl_lock); @@ -235,20 +242,23 @@ void nfs_return_all_delegations(struct super_block *sb) if (clp == NULL) return; restart: - spin_lock(&clp->cl_lock); - list_for_each_entry(delegation, &clp->cl_delegations, super_list) { + rcu_read_lock(); + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { if (delegation->inode->i_sb != sb) continue; inode = igrab(delegation->inode); if (inode == NULL) continue; - nfs_detach_delegation_locked(NFS_I(inode), NULL); + spin_lock(&clp->cl_lock); + delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); spin_unlock(&clp->cl_lock); - __nfs_inode_return_delegation(inode, delegation); + rcu_read_unlock(); + if (delegation != NULL) + __nfs_inode_return_delegation(inode, delegation); iput(inode); goto restart; } - spin_unlock(&clp->cl_lock); + rcu_read_unlock(); } static int nfs_do_expire_all_delegations(void *ptr) @@ -259,23 +269,26 @@ static int nfs_do_expire_all_delegations(void *ptr) allow_signal(SIGKILL); restart: - spin_lock(&clp->cl_lock); if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) goto out; if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) goto out; - list_for_each_entry(delegation, &clp->cl_delegations, super_list) { + rcu_read_lock(); + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { inode = igrab(delegation->inode); if (inode == NULL) continue; - nfs_detach_delegation_locked(NFS_I(inode), NULL); + spin_lock(&clp->cl_lock); + delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); spin_unlock(&clp->cl_lock); - __nfs_inode_return_delegation(inode, delegation); + rcu_read_unlock(); + if (delegation) + __nfs_inode_return_delegation(inode, delegation); iput(inode); goto restart; } + rcu_read_unlock(); out: - spin_unlock(&clp->cl_lock); nfs_put_client(clp); module_put_and_exit(0); } @@ -306,18 +319,21 @@ void nfs_handle_cb_pathdown(struct nfs_client *clp) if (clp == NULL) return; restart: - spin_lock(&clp->cl_lock); - list_for_each_entry(delegation, &clp->cl_delegations, super_list) { + rcu_read_lock(); + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { inode = igrab(delegation->inode); if (inode == NULL) continue; - nfs_detach_delegation_locked(NFS_I(inode), NULL); + spin_lock(&clp->cl_lock); + delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); spin_unlock(&clp->cl_lock); - __nfs_inode_return_delegation(inode, delegation); + rcu_read_unlock(); + if (delegation != NULL) + __nfs_inode_return_delegation(inode, delegation); iput(inode); goto restart; } - spin_unlock(&clp->cl_lock); + rcu_read_unlock(); } struct recall_threadargs { @@ -391,14 +407,14 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs { struct nfs_delegation *delegation; struct inode *res = NULL; - spin_lock(&clp->cl_lock); - list_for_each_entry(delegation, &clp->cl_delegations, super_list) { + rcu_read_lock(); + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) { res = igrab(delegation->inode); break; } } - spin_unlock(&clp->cl_lock); + rcu_read_unlock(); return res; } @@ -408,10 +424,10 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs void nfs_delegation_mark_reclaim(struct nfs_client *clp) { struct nfs_delegation *delegation; - spin_lock(&clp->cl_lock); - list_for_each_entry(delegation, &clp->cl_delegations, super_list) + rcu_read_lock(); + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) delegation->flags |= NFS_DELEGATION_NEED_RECLAIM; - spin_unlock(&clp->cl_lock); + rcu_read_unlock(); } /* @@ -419,39 +435,35 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp) */ void nfs_delegation_reap_unclaimed(struct nfs_client *clp) { - struct nfs_delegation *delegation, *n; - LIST_HEAD(head); - spin_lock(&clp->cl_lock); - list_for_each_entry_safe(delegation, n, &clp->cl_delegations, super_list) { + struct nfs_delegation *delegation; +restart: + rcu_read_lock(); + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) continue; - list_move(&delegation->super_list, &head); - NFS_I(delegation->inode)->delegation = NULL; - NFS_I(delegation->inode)->delegation_state = 0; - } - spin_unlock(&clp->cl_lock); - while(!list_empty(&head)) { - delegation = list_entry(head.next, struct nfs_delegation, super_list); - list_del(&delegation->super_list); - nfs_free_delegation(delegation); + spin_lock(&clp->cl_lock); + delegation = nfs_detach_delegation_locked(NFS_I(delegation->inode), NULL); + spin_unlock(&clp->cl_lock); + rcu_read_unlock(); + if (delegation != NULL) + call_rcu(&delegation->rcu, nfs_free_delegation_callback); + goto restart; } + rcu_read_unlock(); } int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) { - struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_inode *nfsi = NFS_I(inode); struct nfs_delegation *delegation; - int res = 0; + int ret = 0; - if (nfsi->delegation_state == 0) - return 0; - spin_lock(&clp->cl_lock); - delegation = nfsi->delegation; + rcu_read_lock(); + delegation = rcu_dereference(nfsi->delegation); if (delegation != NULL) { memcpy(dst->data, delegation->stateid.data, sizeof(dst->data)); - res = 1; + ret = 1; } - spin_unlock(&clp->cl_lock); - return res; + rcu_read_unlock(); + return ret; } diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 8f79a313516..5874ce7fdba 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -22,6 +22,7 @@ struct nfs_delegation { long flags; loff_t maxsize; __u64 change_attr; + struct rcu_head rcu; }; int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); @@ -45,11 +46,16 @@ int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); static inline int nfs_have_delegation(struct inode *inode, int flags) { + struct nfs_delegation *delegation; + int ret = 0; + flags &= FMODE_READ|FMODE_WRITE; - smp_rmb(); - if ((NFS_I(inode)->delegation_state & flags) == flags) - return 1; - return 0; + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(inode)->delegation); + if (delegation != NULL && (delegation->type & flags) == flags) + ret = 1; + rcu_read_unlock(); + return ret; } #else -- cgit v1.2.3-70-g09d2 From 412c77cee6d6e73fbe1dc3d67f52163efed33fc4 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 3 Jul 2007 16:10:55 -0400 Subject: NFSv4: Defer inode revalidation when setting up a delegation Currently we force a synchronous call to __nfs_revalidate_inode() in nfs_inode_set_delegation(). This not only ensures that we cannot call nfs_inode_set_delegation from an asynchronous context, but it also slows down any call to open(). Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 10 ++++++---- fs/nfs/inode.c | 4 +++- include/linux/nfs_fs.h | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 56f4f6a99d4..20ac403469a 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -124,10 +124,6 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct struct nfs_delegation *delegation; int status = 0; - /* Ensure we first revalidate the attributes and page cache! */ - if ((nfsi->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATTR))) - __nfs_revalidate_inode(NFS_SERVER(inode), inode); - delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); if (delegation == NULL) return -ENOMEM; @@ -154,6 +150,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct status = -EIO; } } + + /* Ensure we revalidate the attributes and page cache! */ + spin_lock(&inode->i_lock); + nfsi->cache_validity |= NFS_INO_REVAL_FORCED; + spin_unlock(&inode->i_lock); + spin_unlock(&clp->cl_lock); kfree(delegation); return status; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 9d5124166d2..3d9fccf4ef9 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1072,8 +1072,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) invalid &= ~NFS_INO_INVALID_DATA; if (data_stable) invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE); - if (!nfs_have_delegation(inode, FMODE_READ)) + if (!nfs_have_delegation(inode, FMODE_READ) || + (nfsi->cache_validity & NFS_INO_REVAL_FORCED)) nfsi->cache_validity |= invalid; + nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED; return 0; out_changed: diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index cf395351cdd..e94971040de 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -184,6 +184,7 @@ struct nfs_inode { #define NFS_INO_INVALID_ACCESS 0x0008 /* cached access cred invalid */ #define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */ #define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */ +#define NFS_INO_REVAL_FORCED 0x0040 /* force revalidation ignoring a delegation */ /* * Bit offsets in flags field -- cgit v1.2.3-70-g09d2 From 0f9f95e0ad1f9d07d77832c5b60f7d30440602ee Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 8 Jul 2007 16:19:56 -0400 Subject: NFSv4: Clean up confirmation of sequence ids... Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 10946415de7..61ba32af4d2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -574,8 +574,8 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) sizeof(data->o_res.stateid.data)); renew_lease(data->o_res.server, data->timestamp); } - nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); + nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); } static void nfs4_open_confirm_release(void *calldata) @@ -674,6 +674,8 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) data->rpc_status = -ENOTDIR; } renew_lease(data->o_res.server, data->timestamp); + if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) + nfs_confirm_seqid(&data->owner->so_seqid, 0); } nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); } @@ -748,7 +750,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) if (status != 0) return status; } - nfs_confirm_seqid(&data->owner->so_seqid, 0); if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); return 0; -- cgit v1.2.3-70-g09d2 From 003707c7225dbd4bf879b6c204743554de0a08d6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 5 Jul 2007 18:07:55 -0400 Subject: NFSv4: Always use the delegation if we have one Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 14 +++++---- fs/nfs/nfs4proc.c | 88 ++++++++++++++++++++++++++++++++++++++++-------------- fs/nfs/nfs4state.c | 28 +++++++++++------ 3 files changed, 94 insertions(+), 36 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 44b56c915f7..4a1c4d80a57 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -122,7 +122,10 @@ struct nfs4_lock_state { /* bits for nfs4_state->flags */ enum { LK_STATE_IN_USE, - NFS_DELEGATED_STATE, + NFS_DELEGATED_STATE, /* Current stateid is delegation */ + NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */ + NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */ + NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ }; struct nfs4_state { @@ -136,11 +139,12 @@ struct nfs4_state { unsigned long flags; /* Do we hold any locks? */ spinlock_t state_lock; /* Protects the lock_states list */ - nfs4_stateid stateid; + nfs4_stateid stateid; /* Current stateid: may be delegation */ + nfs4_stateid open_stateid; /* OPEN stateid */ - unsigned int n_rdonly; - unsigned int n_wronly; - unsigned int n_rdwr; + unsigned int n_rdonly; /* Number of read-only references */ + unsigned int n_wronly; /* Number of write-only references */ + unsigned int n_rdwr; /* Number of read/write references */ int state; /* State on the server (R,W, or RW) */ atomic_t count; }; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 61ba32af4d2..128fe23d3f1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -319,7 +319,7 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) return ret; } -static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) +static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) { switch (open_flags) { case FMODE_WRITE: @@ -331,9 +331,36 @@ static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_ case FMODE_READ|FMODE_WRITE: state->n_rdwr++; } + nfs4_state_set_mode_locked(state, state->state | open_flags); +} + +static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) +{ + if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) + memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); + memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); + switch (open_flags) { + case FMODE_READ: + set_bit(NFS_O_RDONLY_STATE, &state->flags); + break; + case FMODE_WRITE: + set_bit(NFS_O_WRONLY_STATE, &state->flags); + break; + case FMODE_READ|FMODE_WRITE: + set_bit(NFS_O_RDWR_STATE, &state->flags); + } } -static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) +static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) +{ + spin_lock(&state->owner->so_lock); + spin_lock(&state->inode->i_lock); + nfs_set_open_stateid_locked(state, stateid, open_flags); + spin_unlock(&state->inode->i_lock); + spin_unlock(&state->owner->so_lock); +} + +static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) { struct inode *inode = state->inode; @@ -341,9 +368,13 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, /* Protect against nfs4_find_state_byowner() */ spin_lock(&state->owner->so_lock); spin_lock(&inode->i_lock); - memcpy(&state->stateid, stateid, sizeof(state->stateid)); + if (deleg_stateid != NULL) { + memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); + set_bit(NFS_DELEGATED_STATE, &state->flags); + } + if (open_stateid != NULL) + nfs_set_open_stateid_locked(state, open_stateid, open_flags); update_open_stateflags(state, open_flags); - nfs4_state_set_mode_locked(state, state->state | open_flags); spin_unlock(&inode->i_lock); spin_unlock(&state->owner->so_lock); } @@ -352,6 +383,8 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data { struct inode *inode; struct nfs4_state *state = NULL; + struct nfs_delegation *delegation; + nfs4_stateid *deleg_stateid = NULL; if (!(data->f_attr.valid & NFS_ATTR_FATTR)) goto out; @@ -361,13 +394,14 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data state = nfs4_get_open_state(inode, data->owner); if (state == NULL) goto put_inode; - update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags); if (data->o_res.delegation_type != 0) { - struct nfs_inode *nfsi = NFS_I(inode); int delegation_flags = 0; - if (nfsi->delegation) - delegation_flags = nfsi->delegation->flags; + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(inode)->delegation); + if (delegation) + delegation_flags = delegation->flags; + rcu_read_unlock(); if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) nfs_inode_set_delegation(state->inode, data->owner->so_cred, @@ -377,6 +411,12 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data data->owner->so_cred, &data->o_res); } + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(inode)->delegation); + if (delegation != NULL) + deleg_stateid = &delegation->stateid; + update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); + rcu_read_unlock(); put_inode: iput(inode); out: @@ -911,8 +951,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred unlock_kernel(); if (err != 0) goto out_put_open_state; - set_bit(NFS_DELEGATED_STATE, &state->flags); - update_open_stateid(state, &delegation->stateid, open_flags); + update_open_stateid(state, NULL, &delegation->stateid, open_flags); out_ok: nfs4_put_state_owner(sp); up_read(&nfsi->rwsem); @@ -1149,8 +1188,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); switch (task->tk_status) { case 0: - memcpy(&state->stateid, &calldata->res.stateid, - sizeof(state->stateid)); + nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags); renew_lease(server, calldata->timestamp); break; case -NFS4ERR_STALE_STATEID: @@ -1175,26 +1213,32 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) .rpc_resp = &calldata->res, .rpc_cred = state->owner->so_cred, }; - int mode = 0, old_mode; + int clear_rd, clear_wr, clear_rdwr; + int mode; if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) return; - /* Recalculate the new open mode in case someone reopened the file - * while we were waiting in line to be scheduled. - */ + + mode = FMODE_READ|FMODE_WRITE; + clear_rd = clear_wr = clear_rdwr = 0; spin_lock(&state->owner->so_lock); spin_lock(&calldata->inode->i_lock); - mode = old_mode = state->state; + /* Calculate the change in open mode */ if (state->n_rdwr == 0) { - if (state->n_rdonly == 0) + if (state->n_rdonly == 0) { mode &= ~FMODE_READ; - if (state->n_wronly == 0) + clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); + clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); + } + if (state->n_wronly == 0) { mode &= ~FMODE_WRITE; + clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); + clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); + } } - nfs4_state_set_mode_locked(state, mode); spin_unlock(&calldata->inode->i_lock); spin_unlock(&state->owner->so_lock); - if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { + if (!clear_rd && !clear_wr && !clear_rdwr) { /* Note: exit _without_ calling nfs4_close_done */ task->tk_action = NULL; return; @@ -1238,7 +1282,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state) calldata->inode = state->inode; calldata->state = state; calldata->arg.fh = NFS_FH(state->inode); - calldata->arg.stateid = &state->stateid; + calldata->arg.stateid = &state->open_stateid; /* Serialization for the sequence id */ calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); if (calldata->arg.seqid == NULL) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index ac816b303f3..4f78c0d1eab 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -412,7 +412,8 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) { struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; - int oldstate, newstate = 0; + int call_close = 0; + int newstate; atomic_inc(&owner->so_count); /* Protect against nfs4_find_state() */ @@ -428,21 +429,26 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) case FMODE_READ|FMODE_WRITE: state->n_rdwr--; } - oldstate = newstate = state->state; + newstate = FMODE_READ|FMODE_WRITE; if (state->n_rdwr == 0) { - if (state->n_rdonly == 0) + if (state->n_rdonly == 0) { newstate &= ~FMODE_READ; - if (state->n_wronly == 0) + call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags); + call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); + } + if (state->n_wronly == 0) { newstate &= ~FMODE_WRITE; + call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags); + call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); + } + if (newstate == 0) + clear_bit(NFS_DELEGATED_STATE, &state->flags); } - if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { - nfs4_state_set_mode_locked(state, newstate); - oldstate = newstate; - } + nfs4_state_set_mode_locked(state, newstate); spin_unlock(&inode->i_lock); spin_unlock(&owner->so_lock); - if (oldstate == newstate) { + if (!call_close) { nfs4_put_open_state(state); nfs4_put_state_owner(owner); } else @@ -838,6 +844,10 @@ static void nfs4_state_mark_reclaim(struct nfs_client *clp) sp->so_seqid.flags = 0; spin_lock(&sp->so_lock); list_for_each_entry(state, &sp->so_states, open_states) { + clear_bit(NFS_DELEGATED_STATE, &state->flags); + clear_bit(NFS_O_RDONLY_STATE, &state->flags); + clear_bit(NFS_O_WRONLY_STATE, &state->flags); + clear_bit(NFS_O_RDWR_STATE, &state->flags); list_for_each_entry(lock, &state->lock_states, ls_locks) { lock->ls_seqid.counter = 0; lock->ls_seqid.flags = 0; -- cgit v1.2.3-70-g09d2 From 6f43ddccb31b5bd2297878f6f3735d45fd4dfce3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 8 Jul 2007 16:49:11 -0400 Subject: NFSv4: Improve the debugging of bad sequence id errors... Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 4 +++- fs/nfs/nfs4state.c | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 128fe23d3f1..3b59c5ded3f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1079,7 +1079,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int * the user though... */ if (status == -NFS4ERR_BAD_SEQID) { - printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n"); + printk(KERN_WARNING "NFS: v4 server %s " + " returned a bad sequence-id error!\n", + NFS_SERVER(dir)->nfs_client->cl_hostname); exception.retry = 1; continue; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 4f78c0d1eab..4fa4054cdf3 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -38,6 +38,7 @@ * subsequent patch. */ +#include #include #include #include @@ -648,6 +649,12 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) case 0: break; case -NFS4ERR_BAD_SEQID: + if (seqid->sequence->flags & NFS_SEQID_CONFIRMED) + return; + printk(KERN_WARNING "NFS: v4 server returned a bad" + "sequence-id error on an" + "unconfirmed sequence %p!\n", + seqid->sequence); case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_STALE_STATEID: case -NFS4ERR_BAD_STATEID: -- cgit v1.2.3-70-g09d2 From 1b370bc28f90955bccda8be5e7d7047ad1381da7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 7 Jul 2007 08:04:47 -0400 Subject: NFSv4: Allow nfs4_opendata_to_nfs4_state to return errors. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3b59c5ded3f..52ba7630794 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -385,15 +385,19 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data struct nfs4_state *state = NULL; struct nfs_delegation *delegation; nfs4_stateid *deleg_stateid = NULL; + int ret; + ret = -EAGAIN; if (!(data->f_attr.valid & NFS_ATTR_FATTR)) - goto out; + goto err; inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); + ret = PTR_ERR(inode); if (IS_ERR(inode)) - goto out; + goto err; + ret = -ENOMEM; state = nfs4_get_open_state(inode, data->owner); if (state == NULL) - goto put_inode; + goto err_put_inode; if (data->o_res.delegation_type != 0) { int delegation_flags = 0; @@ -417,10 +421,12 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data deleg_stateid = &delegation->stateid; update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); rcu_read_unlock(); -put_inode: iput(inode); -out: return state; +err_put_inode: + iput(inode); +err: + return ERR_PTR(ret); } static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) @@ -453,8 +459,9 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openf if (ret != 0) return ret; newstate = nfs4_opendata_to_nfs4_state(opendata); - if (newstate != NULL) - nfs4_close_state(&opendata->path, newstate, openflags); + if (IS_ERR(newstate)) + return PTR_ERR(newstate); + nfs4_close_state(&opendata->path, newstate, openflags); *res = newstate; return 0; } @@ -631,7 +638,7 @@ static void nfs4_open_confirm_release(void *calldata) goto out_free; nfs_confirm_seqid(&data->owner->so_seqid, 0); state = nfs4_opendata_to_nfs4_state(data); - if (state != NULL) + if (!IS_ERR(state)) nfs4_close_state(&data->path, state, data->o_arg.open_flags); out_free: nfs4_opendata_put(data); @@ -736,7 +743,7 @@ static void nfs4_open_release(void *calldata) goto out_free; nfs_confirm_seqid(&data->owner->so_seqid, 0); state = nfs4_opendata_to_nfs4_state(data); - if (state != NULL) + if (!IS_ERR(state)) nfs4_close_state(&data->path, state, data->o_arg.open_flags); out_free: nfs4_opendata_put(data); @@ -1036,9 +1043,9 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct if (opendata->o_arg.open_flags & O_EXCL) nfs4_exclusive_attrset(opendata, sattr); - status = -ENOMEM; state = nfs4_opendata_to_nfs4_state(opendata); - if (state == NULL) + status = PTR_ERR(state); + if (IS_ERR(state)) goto err_opendata_put; nfs4_opendata_put(opendata); nfs4_put_state_owner(sp); -- cgit v1.2.3-70-g09d2 From 3e309914a15333a5493058e4927e979c7434ae44 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 7 Jul 2007 13:19:59 -0400 Subject: NFSv4: Clean up _nfs4_proc_open() Use a flag instead of the 'data->rpc_status = -ENOMEM hack. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 52ba7630794..05afb7ba3bc 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -226,6 +226,7 @@ struct nfs4_opendata { struct nfs4_state_owner *owner; struct iattr attrs; unsigned long timestamp; + unsigned int rpc_done : 1; int rpc_status; int cancelled; }; @@ -620,6 +621,7 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) memcpy(data->o_res.stateid.data, data->c_res.stateid.data, sizeof(data->o_res.stateid.data)); renew_lease(data->o_res.server, data->timestamp); + data->rpc_done = 1; } nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); @@ -634,7 +636,7 @@ static void nfs4_open_confirm_release(void *calldata) if (data->cancelled == 0) goto out_free; /* In case of error, no cleanup! */ - if (data->rpc_status != 0) + if (!data->rpc_done) goto out_free; nfs_confirm_seqid(&data->owner->so_seqid, 0); state = nfs4_opendata_to_nfs4_state(data); @@ -660,11 +662,8 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) int status; kref_get(&data->kref); - /* - * If rpc_run_task() ends up calling ->rpc_release(), we - * want to ensure that it takes the 'error' code path. - */ - data->rpc_status = -ENOMEM; + data->rpc_done = 0; + data->rpc_status = 0; task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); if (IS_ERR(task)) return PTR_ERR(task); @@ -725,6 +724,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) nfs_confirm_seqid(&data->owner->so_seqid, 0); } nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); + data->rpc_done = 1; } static void nfs4_open_release(void *calldata) @@ -736,7 +736,7 @@ static void nfs4_open_release(void *calldata) if (data->cancelled == 0) goto out_free; /* In case of error, no cleanup! */ - if (data->rpc_status != 0) + if (data->rpc_status != 0 || !data->rpc_done) goto out_free; /* In case we need an open_confirm, no cleanup! */ if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) @@ -768,11 +768,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) int status; kref_get(&data->kref); - /* - * If rpc_run_task() ends up calling ->rpc_release(), we - * want to ensure that it takes the 'error' code path. - */ - data->rpc_status = -ENOMEM; + data->rpc_done = 0; + data->rpc_status = 0; data->cancelled = 0; task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); if (IS_ERR(task)) @@ -784,7 +781,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) } else status = data->rpc_status; rpc_put_task(task); - if (status != 0) + if (status != 0 || !data->rpc_done) return status; if (o_arg->open_flags & O_CREAT) { -- cgit v1.2.3-70-g09d2 From aac00a8d0a53097063da532cbdf0b8775a4dcd53 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 5 Jul 2007 19:02:21 -0400 Subject: NFSv4: Check for the existence of a delegation in nfs4_open_prepare() We should not be calling open() on an inode that has a delegation unless we're doing a reclaim. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 195 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 107 insertions(+), 88 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 05afb7ba3bc..ea332e831d7 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -65,6 +65,7 @@ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *) static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); +static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags); /* Prevent leaks of NFSv4 errors into userland */ int nfs4_map_errors(int err) @@ -224,6 +225,7 @@ struct nfs4_opendata { struct path path; struct dentry *dir; struct nfs4_state_owner *owner; + struct nfs4_state *state; struct iattr attrs; unsigned long timestamp; unsigned int rpc_done : 1; @@ -296,6 +298,8 @@ static void nfs4_opendata_free(struct kref *kref) struct nfs4_opendata, kref); nfs_free_seqid(p->o_arg.seqid); + if (p->state != NULL) + nfs4_put_open_state(p->state); nfs4_put_state_owner(p->owner); dput(p->dir); dput(p->path.dentry); @@ -320,6 +324,15 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) return ret; } +static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) +{ + if ((delegation->type & open_flags) != open_flags) + return 0; + if (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) + return 0; + return 1; +} + static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) { switch (open_flags) { @@ -380,6 +393,65 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_sta spin_unlock(&state->owner->so_lock); } +static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags) +{ + struct nfs_delegation *delegation; + + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(inode)->delegation); + if (delegation == NULL || (delegation->type & open_flags) == open_flags) { + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + nfs_inode_return_delegation(inode); +} + +static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata) +{ + struct nfs4_state *state = opendata->state; + struct nfs_inode *nfsi = NFS_I(state->inode); + struct nfs_delegation *delegation; + int open_mode = opendata->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL); + nfs4_stateid stateid; + int ret = -EAGAIN; + + rcu_read_lock(); + delegation = rcu_dereference(nfsi->delegation); + if (delegation == NULL) + goto out_unlock; + for (;;) { + if (!can_open_delegated(delegation, open_mode)) + break; + /* Save the delegation */ + memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); + rcu_read_unlock(); + lock_kernel(); + ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode); + unlock_kernel(); + if (ret != 0) + goto out; + ret = -EAGAIN; + rcu_read_lock(); + delegation = rcu_dereference(nfsi->delegation); + if (delegation == NULL) + break; + /* Is the delegation still valid? */ + if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0) + continue; + rcu_read_unlock(); + update_open_stateid(state, NULL, &stateid, open_mode); + goto out_return_state; + } +out_unlock: + rcu_read_unlock(); +out: + return ERR_PTR(ret); +out_return_state: + atomic_inc(&state->count); + return state; +} + static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) { struct inode *inode; @@ -388,6 +460,11 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data nfs4_stateid *deleg_stateid = NULL; int ret; + if (!data->rpc_done) { + state = nfs4_try_open_delegated(data); + goto out; + } + ret = -EAGAIN; if (!(data->f_attr.valid & NFS_ATTR_FATTR)) goto err; @@ -423,6 +500,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); rcu_read_unlock(); iput(inode); +out: return state; err_put_inode: iput(inode); @@ -690,6 +768,23 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) return; + /* + * Check if we still need to send an OPEN call, or if we can use + * a delegation instead. + */ + if (data->state != NULL) { + struct nfs_delegation *delegation; + + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); + if (delegation != NULL && + (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) { + rcu_read_unlock(); + task->tk_action = NULL; + return; + } + rcu_read_unlock(); + } /* Update sequence id. */ data->o_arg.id = sp->so_owner_id.id; data->o_arg.clientid = sp->so_client->cl_clientid; @@ -906,90 +1001,6 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta return ret; } -/* - * Returns a referenced nfs4_state if there is an open delegation on the file - */ -static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) -{ - struct nfs_delegation *delegation; - struct nfs_server *server = NFS_SERVER(inode); - struct nfs_client *clp = server->nfs_client; - struct nfs_inode *nfsi = NFS_I(inode); - struct nfs4_state_owner *sp = NULL; - struct nfs4_state *state = NULL; - int open_flags = flags & (FMODE_READ|FMODE_WRITE); - int err; - - err = -ENOMEM; - if (!(sp = nfs4_get_state_owner(server, cred))) { - dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); - return err; - } - err = nfs4_recover_expired_lease(server); - if (err != 0) - goto out_put_state_owner; - /* Protect against reboot recovery - NOTE ORDER! */ - down_read(&clp->cl_sem); - /* Protect against delegation recall */ - down_read(&nfsi->rwsem); - delegation = NFS_I(inode)->delegation; - err = -ENOENT; - if (delegation == NULL || (delegation->type & open_flags) != open_flags) - goto out_err; - err = -ENOMEM; - state = nfs4_get_open_state(inode, sp); - if (state == NULL) - goto out_err; - - err = -ENOENT; - if ((state->state & open_flags) == open_flags) { - spin_lock(&inode->i_lock); - update_open_stateflags(state, open_flags); - spin_unlock(&inode->i_lock); - goto out_ok; - } else if (state->state != 0) - goto out_put_open_state; - - lock_kernel(); - err = _nfs4_do_access(inode, cred, open_flags); - unlock_kernel(); - if (err != 0) - goto out_put_open_state; - update_open_stateid(state, NULL, &delegation->stateid, open_flags); -out_ok: - nfs4_put_state_owner(sp); - up_read(&nfsi->rwsem); - up_read(&clp->cl_sem); - *res = state; - return 0; -out_put_open_state: - nfs4_put_open_state(state); -out_err: - up_read(&nfsi->rwsem); - up_read(&clp->cl_sem); - if (err != -EACCES) - nfs_inode_return_delegation(inode); -out_put_state_owner: - nfs4_put_state_owner(sp); - return err; -} - -static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred) -{ - struct nfs4_exception exception = { }; - struct nfs4_state *res = ERR_PTR(-EIO); - int err; - - do { - err = _nfs4_open_delegated(inode, flags, cred, &res); - if (err == 0) - break; - res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(inode), - err, &exception)); - } while (exception.retry); - return res; -} - /* * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-* * fields corresponding to attributes that were used to store the verifier. @@ -1016,7 +1027,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct struct nfs_server *server = NFS_SERVER(dir); struct nfs_client *clp = server->nfs_client; struct nfs4_opendata *opendata; - int status; + int status; /* Protect against reboot recovery conflicts */ status = -ENOMEM; @@ -1027,12 +1038,17 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct status = nfs4_recover_expired_lease(server); if (status != 0) goto err_put_state_owner; + if (path->dentry->d_inode != NULL) + nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE)); down_read(&clp->cl_sem); status = -ENOMEM; opendata = nfs4_opendata_alloc(path, sp, flags, sattr); if (opendata == NULL) goto err_release_rwsem; + if (path->dentry->d_inode != NULL) + opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); + status = _nfs4_proc_open(opendata); if (status != 0) goto err_opendata_put; @@ -1099,6 +1115,11 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int exception.retry = 1; continue; } + if (status == -EAGAIN) { + /* We must have found a delegation */ + exception.retry = 1; + continue; + } res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), status, &exception)); } while (exception.retry); @@ -1390,9 +1411,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); if (IS_ERR(cred)) return PTR_ERR(cred); - state = nfs4_open_delegated(dentry->d_inode, openflags, cred); - if (IS_ERR(state)) - state = nfs4_do_open(dir, &path, openflags, NULL, cred); + state = nfs4_do_open(dir, &path, openflags, NULL, cred); put_rpccred(cred); if (IS_ERR(state)) { switch (PTR_ERR(state)) { -- cgit v1.2.3-70-g09d2 From 6ee412689027dc7954453aed392ab5c7599c0f73 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 8 Jul 2007 14:11:36 -0400 Subject: NFSv4: Don't call OPEN if we already have an open stateid for a file If we already have a stateid with the correct open mode for a given file, then we can reuse that stateid instead of re-issuing an OPEN call without violating the close-to-open caching semantics. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ea332e831d7..1de07661925 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -324,6 +324,24 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) return ret; } +static int can_open_cached(struct nfs4_state *state, int mode) +{ + int ret = 0; + switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { + case FMODE_READ: + ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; + ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; + break; + case FMODE_WRITE: + ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; + ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; + break; + case FMODE_READ|FMODE_WRITE: + ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; + } + return ret; +} + static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) { if ((delegation->type & open_flags) != open_flags) @@ -407,7 +425,7 @@ static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open nfs_inode_return_delegation(inode); } -static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata) +static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) { struct nfs4_state *state = opendata->state; struct nfs_inode *nfsi = NFS_I(state->inode); @@ -418,9 +436,19 @@ static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata rcu_read_lock(); delegation = rcu_dereference(nfsi->delegation); - if (delegation == NULL) - goto out_unlock; for (;;) { + if (can_open_cached(state, open_mode)) { + spin_lock(&state->owner->so_lock); + if (can_open_cached(state, open_mode)) { + update_open_stateflags(state, open_mode); + spin_unlock(&state->owner->so_lock); + rcu_read_unlock(); + goto out_return_state; + } + spin_unlock(&state->owner->so_lock); + } + if (delegation == NULL) + break; if (!can_open_delegated(delegation, open_mode)) break; /* Save the delegation */ @@ -434,8 +462,9 @@ static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata ret = -EAGAIN; rcu_read_lock(); delegation = rcu_dereference(nfsi->delegation); + /* If no delegation, try a cached open */ if (delegation == NULL) - break; + continue; /* Is the delegation still valid? */ if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0) continue; @@ -443,7 +472,6 @@ static struct nfs4_state *nfs4_try_open_delegated(struct nfs4_opendata *opendata update_open_stateid(state, NULL, &stateid, open_mode); goto out_return_state; } -out_unlock: rcu_read_unlock(); out: return ERR_PTR(ret); @@ -461,7 +489,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data int ret; if (!data->rpc_done) { - state = nfs4_try_open_delegated(data); + state = nfs4_try_open_cached(data); goto out; } @@ -775,13 +803,14 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) if (data->state != NULL) { struct nfs_delegation *delegation; + if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL))) + goto out_no_action; rcu_read_lock(); delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) { rcu_read_unlock(); - task->tk_action = NULL; - return; + goto out_no_action; } rcu_read_unlock(); } @@ -792,6 +821,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; data->timestamp = jiffies; rpc_call_setup(task, &msg, 0); + return; +out_no_action: + task->tk_action = NULL; + } static void nfs4_open_done(struct rpc_task *task, void *calldata) -- cgit v1.2.3-70-g09d2 From 1ac7e2fd35905f3d44df06568bca5f9d140369b3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 8 Jul 2007 21:04:15 -0400 Subject: NFSv4: Clean up the callers of nfs4_open_recover_helper() Rely on nfs4_try_open_cached() when appropriate. Also fix an RCU violation in _nfs4_do_open_reclaim() Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1de07661925..3a2af805376 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -602,6 +602,19 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * if (newstate != state) return -ESTALE; } + /* + * We may have performed cached opens for all three recoveries. + * Check if we need to update the current stateid. + */ + if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && + memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { + spin_lock(&state->owner->so_lock); + spin_lock(&state->inode->i_lock); + if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) + memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); + spin_unlock(&state->inode->i_lock); + spin_unlock(&state->owner->so_lock); + } return 0; } @@ -611,26 +624,22 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * */ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) { - struct nfs_delegation *delegation = NFS_I(state->inode)->delegation; + struct nfs_delegation *delegation; struct nfs4_opendata *opendata; int delegation_type = 0; int status; - if (delegation != NULL) { - if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { - memcpy(&state->stateid, &delegation->stateid, - sizeof(state->stateid)); - set_bit(NFS_DELEGATED_STATE, &state->flags); - return 0; - } - delegation_type = delegation->type; - } opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); if (opendata == NULL) return -ENOMEM; opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; opendata->o_arg.fh = NFS_FH(state->inode); nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh); + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(state->inode)->delegation); + if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) + delegation_type = delegation->flags; + rcu_read_unlock(); opendata->o_arg.u.delegation_type = delegation_type; status = nfs4_open_recover(opendata, state); nfs4_opendata_put(opendata); @@ -980,21 +989,10 @@ static int nfs4_recover_expired_lease(struct nfs_server *server) */ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) { - struct inode *inode = state->inode; - struct nfs_delegation *delegation = NFS_I(inode)->delegation; struct nfs4_opendata *opendata; - int openflags = state->state & (FMODE_READ|FMODE_WRITE); int ret; - if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { - ret = _nfs4_do_access(inode, ctx->cred, openflags); - if (ret < 0) - return ret; - memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); - set_bit(NFS_DELEGATED_STATE, &state->flags); - return 0; - } - opendata = nfs4_opendata_alloc(&ctx->path, state->owner, openflags, NULL); + opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); if (opendata == NULL) return -ENOMEM; ret = nfs4_open_recover(opendata, state); -- cgit v1.2.3-70-g09d2 From 8bda4e4c98d14566fc1a354c62fb59d70cc49b97 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 9 Jul 2007 10:45:42 -0400 Subject: NFSv4: Fix up stateid locking... We really don't need to grab both the state->so_owner and the inode->i_lock. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 2 ++ fs/nfs/nfs4proc.c | 27 +++++++++++---------------- fs/nfs/nfs4state.c | 10 ++++++---- 3 files changed, 19 insertions(+), 20 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 4a1c4d80a57..dd1aa2b598c 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -139,9 +139,11 @@ struct nfs4_state { unsigned long flags; /* Do we hold any locks? */ spinlock_t state_lock; /* Protects the lock_states list */ + seqlock_t seqlock; /* Protects the stateid/open_stateid */ nfs4_stateid stateid; /* Current stateid: may be delegation */ nfs4_stateid open_stateid; /* OPEN stateid */ + /* The following 3 fields are protected by owner->so_lock */ unsigned int n_rdonly; /* Number of read-only references */ unsigned int n_wronly; /* Number of write-only references */ unsigned int n_rdwr; /* Number of read/write references */ diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3a2af805376..ba86ec654c2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -385,29 +385,28 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid * static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) { - spin_lock(&state->owner->so_lock); - spin_lock(&state->inode->i_lock); + write_seqlock(&state->seqlock); nfs_set_open_stateid_locked(state, stateid, open_flags); - spin_unlock(&state->inode->i_lock); - spin_unlock(&state->owner->so_lock); + write_sequnlock(&state->seqlock); } static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) { - struct inode *inode = state->inode; - open_flags &= (FMODE_READ|FMODE_WRITE); - /* Protect against nfs4_find_state_byowner() */ - spin_lock(&state->owner->so_lock); - spin_lock(&inode->i_lock); + /* + * Protect the call to nfs4_state_set_mode_locked and + * serialise the stateid update + */ + write_seqlock(&state->seqlock); if (deleg_stateid != NULL) { memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); set_bit(NFS_DELEGATED_STATE, &state->flags); } if (open_stateid != NULL) nfs_set_open_stateid_locked(state, open_stateid, open_flags); + write_sequnlock(&state->seqlock); + spin_lock(&state->owner->so_lock); update_open_stateflags(state, open_flags); - spin_unlock(&inode->i_lock); spin_unlock(&state->owner->so_lock); } @@ -608,12 +607,10 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * */ if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { - spin_lock(&state->owner->so_lock); - spin_lock(&state->inode->i_lock); + write_seqlock(&state->seqlock); if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); - spin_unlock(&state->inode->i_lock); - spin_unlock(&state->owner->so_lock); + write_sequnlock(&state->seqlock); } return 0; } @@ -1280,7 +1277,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) mode = FMODE_READ|FMODE_WRITE; clear_rd = clear_wr = clear_rdwr = 0; spin_lock(&state->owner->so_lock); - spin_lock(&calldata->inode->i_lock); /* Calculate the change in open mode */ if (state->n_rdwr == 0) { if (state->n_rdonly == 0) { @@ -1294,7 +1290,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); } } - spin_unlock(&calldata->inode->i_lock); spin_unlock(&state->owner->so_lock); if (!clear_rd && !clear_wr && !clear_rdwr) { /* Note: exit _without_ calling nfs4_close_done */ diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 4fa4054cdf3..523cc2cbb5e 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -307,6 +307,7 @@ nfs4_alloc_open_state(void) atomic_set(&state->count, 1); INIT_LIST_HEAD(&state->lock_states); spin_lock_init(&state->state_lock); + seqlock_init(&state->seqlock); return state; } @@ -411,7 +412,6 @@ void nfs4_put_open_state(struct nfs4_state *state) */ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) { - struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; int call_close = 0; int newstate; @@ -419,7 +419,6 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) atomic_inc(&owner->so_count); /* Protect against nfs4_find_state() */ spin_lock(&owner->so_lock); - spin_lock(&inode->i_lock); switch (mode & (FMODE_READ | FMODE_WRITE)) { case FMODE_READ: state->n_rdonly--; @@ -446,7 +445,6 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) clear_bit(NFS_DELEGATED_STATE, &state->flags); } nfs4_state_set_mode_locked(state, newstate); - spin_unlock(&inode->i_lock); spin_unlock(&owner->so_lock); if (!call_close) { @@ -599,8 +597,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) { struct nfs4_lock_state *lsp; + int seq; - memcpy(dst, &state->stateid, sizeof(*dst)); + do { + seq = read_seqbegin(&state->seqlock); + memcpy(dst, &state->stateid, sizeof(*dst)); + } while (read_seqretry(&state->seqlock, seq)); if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) return; -- cgit v1.2.3-70-g09d2 From 9eaa67c6a5b77f248c4703d81c4a6c6434e35385 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:12:19 -0400 Subject: NFS: Clean-up: use correct type when converting NFS blocks to local blocks inode->i_blocks is a blkcnt_t these days, which can be a u64 or unsigned long, depending on the setting of CONFIG_LSF. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index ad2b40db1e6..76cf55d5710 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -183,9 +183,9 @@ unsigned long nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp) /* * Calculate the number of 512byte blocks used. */ -static inline unsigned long nfs_calc_block_size(u64 tsize) +static inline blkcnt_t nfs_calc_block_size(u64 tsize) { - loff_t used = (tsize + 511) >> 9; + blkcnt_t used = (tsize + 511) >> 9; return (used > ULONG_MAX) ? ULONG_MAX : used; } -- cgit v1.2.3-70-g09d2 From 5680d48be88d12cd987e5579a6072a4ca34ca6ea Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:12:24 -0400 Subject: NFS: Clean-up: Define macros for maximum host and export path name lengths Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 4 ++-- include/linux/nfs_mount.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 14c7923697d..e7d19708583 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -867,12 +867,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type, } } - p = nfs_copy_user_string(NULL, &data->hostname, 256); + p = nfs_copy_user_string(NULL, &data->hostname, NFS4_MAXNAMLEN); if (IS_ERR(p)) goto out_err; hostname = p; - p = nfs_copy_user_string(NULL, &data->mnt_path, 1024); + p = nfs_copy_user_string(NULL, &data->mnt_path, NFS4_MAXPATHLEN); if (IS_ERR(p)) goto out_err; mntpath = p; diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h index cc8b9c59acb..0b82a17c705 100644 --- a/include/linux/nfs_mount.h +++ b/include/linux/nfs_mount.h @@ -37,7 +37,7 @@ struct nfs_mount_data { int acdirmin; /* 1 */ int acdirmax; /* 1 */ struct sockaddr_in addr; /* 1 */ - char hostname[256]; /* 1 */ + char hostname[NFS_MAXNAMLEN + 1]; /* 1 */ int namlen; /* 2 */ unsigned int bsize; /* 3 */ struct nfs3_fh root; /* 4 */ -- cgit v1.2.3-70-g09d2 From 29eb981a3b8eb4e61cd5b9da835768045d0446cb Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:12:30 -0400 Subject: NFS: Clean-up: Replace nfs_copy_user_string with strndup_user The new string utility function strndup_user can be used instead of nfs_copy_user_string, eliminating an unnecessary duplication of function. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 53 ++++++++++++++++------------------------------------- 1 file changed, 16 insertions(+), 37 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e7d19708583..04ad881eac7 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -785,27 +785,6 @@ static void nfs4_fill_super(struct super_block *sb) nfs_initialise_sb(sb); } -static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) -{ - void *p = NULL; - - if (!src->len) - return ERR_PTR(-EINVAL); - if (src->len < maxlen) - maxlen = src->len; - if (dst == NULL) { - p = dst = kmalloc(maxlen + 1, GFP_KERNEL); - if (p == NULL) - return ERR_PTR(-ENOMEM); - } - if (copy_from_user(dst, src->data, maxlen)) { - kfree(p); - return ERR_PTR(-EFAULT); - } - dst[maxlen] = '\0'; - return dst; -} - /* * Get the superblock for an NFS4 mountpoint */ @@ -819,8 +798,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, rpc_authflavor_t authflavour; struct nfs_fh mntfh; struct dentry *mntroot; - char *mntpath = NULL, *hostname = NULL, ip_addr[16]; - void *p; + char *p, *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; int error; if (data == NULL) { @@ -857,39 +835,39 @@ static int nfs4_get_sb(struct file_system_type *fs_type, dprintk("%s: Invalid number of RPC auth flavours %d.\n", __FUNCTION__, data->auth_flavourlen); error = -EINVAL; - goto out_err_noserver; + goto out; } if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { error = -EFAULT; - goto out_err_noserver; + goto out; } } - p = nfs_copy_user_string(NULL, &data->hostname, NFS4_MAXNAMLEN); + p = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); if (IS_ERR(p)) goto out_err; hostname = p; - p = nfs_copy_user_string(NULL, &data->mnt_path, NFS4_MAXPATHLEN); + p = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN); if (IS_ERR(p)) goto out_err; mntpath = p; dprintk("MNTPATH: %s\n", mntpath); - p = nfs_copy_user_string(ip_addr, &data->client_addr, - sizeof(ip_addr) - 1); + p = strndup_user(data->client_addr.data, 16); if (IS_ERR(p)) goto out_err; + ip_addr = p; /* Get a volume representation */ server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr, authflavour, &mntfh); if (IS_ERR(server)) { error = PTR_ERR(server); - goto out_err_noserver; + goto out; } /* Get a superblock - note that we may end up sharing one that already exists */ @@ -919,25 +897,26 @@ static int nfs4_get_sb(struct file_system_type *fs_type, s->s_flags |= MS_ACTIVE; mnt->mnt_sb = s; mnt->mnt_root = mntroot; + error = 0; + +out: + kfree(ip_addr); kfree(mntpath); kfree(hostname); - return 0; + return error; out_err: error = PTR_ERR(p); - goto out_err_noserver; + goto out; out_free: nfs_free_server(server); -out_err_noserver: - kfree(mntpath); - kfree(hostname); - return error; + goto out; error_splat_super: up_write(&s->s_umount); deactivate_super(s); - goto out_err_noserver; + goto out; } static void nfs4_kill_super(struct super_block *sb) -- cgit v1.2.3-70-g09d2 From 0655960f76922a720ad14a510ed91a51395e742b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:12:35 -0400 Subject: NFS: Clean up error handling in nfs_get_sb The error return logic in nfs_get_sb now matches nfs4_get_sb, and is more maintainable. A subsequent patch will take advantage of this simplification. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 04ad881eac7..aab5cd61725 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -633,13 +633,13 @@ static int nfs_get_sb(struct file_system_type *fs_type, /* Validate the mount data */ error = nfs_validate_mount_data(data, &mntfh); if (error < 0) - return error; + goto out; /* Get a volume representation */ server = nfs_create_server(data, &mntfh); if (IS_ERR(server)) { error = PTR_ERR(server); - goto out_err_noserver; + goto out; } /* Get a superblock - note that we may end up sharing one that already exists */ @@ -669,17 +669,19 @@ static int nfs_get_sb(struct file_system_type *fs_type, s->s_flags |= MS_ACTIVE; mnt->mnt_sb = s; mnt->mnt_root = mntroot; - return 0; + error = 0; + +out: + return error; out_err_nosb: nfs_free_server(server); -out_err_noserver: - return error; + goto out; error_splat_super: up_write(&s->s_umount); deactivate_super(s); - return error; + goto out; } /* -- cgit v1.2.3-70-g09d2 From 4d81cd16112f86dc279d90ef7a24f2b1be339c3c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:12:40 -0400 Subject: NFS: Clean-up: fix a compiler warning in fs/nfs/super.c /home/cel/linux/fs/nfs/super.c: In function 'nfs_pseudoflavour_to_name': /home/cel/linux/fs/nfs/super.c:270: warning: comparison between signed and unsigned Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index aab5cd61725..6eac5bf911e 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -263,11 +263,11 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) { RPC_AUTH_GSS_SPKM, "spkm" }, { RPC_AUTH_GSS_SPKMI, "spkmi" }, { RPC_AUTH_GSS_SPKMP, "spkmp" }, - { -1, "unknown" } + { UINT_MAX, "unknown" } }; int i; - for (i=0; sec_flavours[i].flavour != -1; i++) { + for (i = 0; sec_flavours[i].flavour != UINT_MAX; i++) { if (sec_flavours[i].flavour == flavour) break; } -- cgit v1.2.3-70-g09d2 From fc50d58fd053862d6bafcf92f1ef2961296f3a1c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:12:46 -0400 Subject: NFS: Clean-up: Refactor IP address sanity checks in NFS client NFS and NFSv4 mounts can now share server address sanity checking. And, it provides an easy mechanism for adding IPv6 address checking at some later point. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 6eac5bf911e..7f5bc28ea8d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -446,6 +446,23 @@ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) rpc_killall_tasks(rpc); } +/* + * Sanity-check a server address provided by the mount command + */ +static int nfs_verify_server_address(struct sockaddr *addr) +{ + switch (addr->sa_family) { + case AF_INET: { + struct sockaddr_in *sa = (struct sockaddr_in *) addr; + if (sa->sin_addr.s_addr != INADDR_ANY) + return 1; + break; + } + } + + return 0; +} + /* * Validate the NFS2/NFS3 mount data * - fills in the mount root filehandle @@ -501,7 +518,7 @@ static int nfs_validate_mount_data(struct nfs_mount_data *data, #endif /* CONFIG_NFS_V3 */ /* We now require that the mount process passes the remote address */ - if (data->addr.sin_addr.s_addr == INADDR_ANY) { + if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) { dprintk("%s: mount program didn't pass remote address!\n", __FUNCTION__); return -EINVAL; @@ -819,13 +836,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type, if (copy_from_user(&addr, data->host_addr, sizeof(addr))) return -EFAULT; - if (addr.sin_family != AF_INET || - addr.sin_addr.s_addr == INADDR_ANY - ) { + if (!nfs_verify_server_address((struct sockaddr *) &addr)) { dprintk("%s: mount program didn't pass remote IP address!\n", __FUNCTION__); return -EINVAL; } + /* RFC3530: The default port for NFS is 2049 */ if (addr.sin_port == 0) addr.sin_port = htons(NFS_PORT); -- cgit v1.2.3-70-g09d2 From 5df36e78da9db1c5f02b429116ed98902bcc75e5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:12:56 -0400 Subject: NFS: Clean up nfs_validate_mount_data Move error handling code out of the main code path. The switch statement was also improperly indented, according to Documentation/CodingStyle. This prepares nfs_validate_mount_data for the addition of option string parsing. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 125 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 67 insertions(+), 58 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 7f5bc28ea8d..baf75e9bd3f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -470,77 +470,86 @@ static int nfs_verify_server_address(struct sockaddr *addr) static int nfs_validate_mount_data(struct nfs_mount_data *data, struct nfs_fh *mntfh) { - if (data == NULL) { - dprintk("%s: missing data argument\n", __FUNCTION__); - return -EINVAL; - } - - if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { - dprintk("%s: bad mount version\n", __FUNCTION__); - return -EINVAL; - } + if (data == NULL) + goto out_no_data; switch (data->version) { - case 1: - data->namlen = 0; - case 2: - data->bsize = 0; - case 3: - if (data->flags & NFS_MOUNT_VER3) { - dprintk("%s: mount structure version %d does not support NFSv3\n", - __FUNCTION__, - data->version); - return -EINVAL; - } - data->root.size = NFS2_FHSIZE; - memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); - case 4: - if (data->flags & NFS_MOUNT_SECFLAVOUR) { - dprintk("%s: mount structure version %d does not support strong security\n", - __FUNCTION__, - data->version); - return -EINVAL; - } - case 5: - memset(data->context, 0, sizeof(data->context)); + case 1: + data->namlen = 0; + case 2: + data->bsize = 0; + case 3: + if (data->flags & NFS_MOUNT_VER3) + goto out_no_v3; + data->root.size = NFS2_FHSIZE; + memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); + case 4: + if (data->flags & NFS_MOUNT_SECFLAVOUR) + goto out_no_sec; + case 5: + memset(data->context, 0, sizeof(data->context)); + case 6: + if (data->flags & NFS_MOUNT_VER3) + mntfh->size = data->root.size; + else + mntfh->size = NFS2_FHSIZE; + + if (mntfh->size > sizeof(mntfh->data)) + goto out_invalid_fh; + + memcpy(mntfh->data, data->root.data, mntfh->size); + if (mntfh->size < sizeof(mntfh->data)) + memset(mntfh->data + mntfh->size, 0, + sizeof(mntfh->data) - mntfh->size); + break; + default: + goto out_bad_version; } - /* Set the pseudoflavor */ if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) data->pseudoflavor = RPC_AUTH_UNIX; #ifndef CONFIG_NFS_V3 - /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ - if (data->flags & NFS_MOUNT_VER3) { - dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); - return -EPROTONOSUPPORT; - } -#endif /* CONFIG_NFS_V3 */ + if (data->flags & NFS_MOUNT_VER3) + goto out_v3_not_compiled; +#endif /* !CONFIG_NFS_V3 */ - /* We now require that the mount process passes the remote address */ - if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) { - dprintk("%s: mount program didn't pass remote address!\n", - __FUNCTION__); - return -EINVAL; - } + if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) + goto out_no_address; - /* Prepare the root filehandle */ - if (data->flags & NFS_MOUNT_VER3) - mntfh->size = data->root.size; - else - mntfh->size = NFS2_FHSIZE; + return 0; - if (mntfh->size > sizeof(mntfh->data)) { - dprintk("%s: invalid root filehandle\n", __FUNCTION__); - return -EINVAL; - } +out_no_data: + dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n"); + return -EINVAL; - memcpy(mntfh->data, data->root.data, mntfh->size); - if (mntfh->size < sizeof(mntfh->data)) - memset(mntfh->data + mntfh->size, 0, - sizeof(mntfh->data) - mntfh->size); +out_no_v3: + dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n", + data->version); + return -EINVAL; - return 0; +out_no_sec: + dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n"); + return -EINVAL; + +out_bad_version: + dfprintk(MOUNT, "NFS: bad nfs_mount_data version %d\n", + data->version); + return -EINVAL; + +#ifndef CONFIG_NFS_V3 +out_v3_not_compiled: + dfprintk(MOUNT, "NFS: NFSv3 is not compiled into kernel\n"); + return -EPROTONOSUPPORT; +#endif /* !CONFIG_NFS_V3 */ + +out_no_address: + dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); + return -EINVAL; + +out_invalid_fh: + dfprintk(MOUNT, "NFS: invalid root filehandle\n"); + return -EINVAL; } /* -- cgit v1.2.3-70-g09d2 From f0768ebd09385551277fcbc8b28c29eb491bf9e2 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:01 -0400 Subject: NFS: Introduce nfs4_validate_mount_options Refactor NFSv4 mount processing to break out mount data validation in the same way it's broken out in the NFSv2/v3 mount path. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 153 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 64 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index baf75e9bd3f..ed3ec4477a0 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -813,6 +813,89 @@ static void nfs4_fill_super(struct super_block *sb) nfs_initialise_sb(sb); } +/* + * Validate NFSv4 mount options + */ +static int nfs4_validate_mount_data(struct nfs4_mount_data **options, + const char *dev_name, + struct sockaddr_in *addr, + rpc_authflavor_t *authflavour, + char **hostname, + char **mntpath, + char **ip_addr) +{ + struct nfs4_mount_data *data = *options; + char *c; + + if (data == NULL) + goto out_no_data; + + switch (data->version) { + case 1: + if (data->host_addrlen != sizeof(*addr)) + goto out_no_address; + if (copy_from_user(addr, data->host_addr, sizeof(*addr))) + return -EFAULT; + if (addr->sin_port == 0) + addr->sin_port = htons(NFS_PORT); + if (!nfs_verify_server_address((struct sockaddr *) addr)) + goto out_no_address; + + switch (data->auth_flavourlen) { + case 0: + *authflavour = RPC_AUTH_UNIX; + break; + case 1: + if (copy_from_user(authflavour, data->auth_flavours, + sizeof(*authflavour))) + return -EFAULT; + break; + default: + goto out_inval_auth; + } + + c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); + if (IS_ERR(c)) + return PTR_ERR(c); + *hostname = c; + + c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN); + if (IS_ERR(c)) + return PTR_ERR(c); + *mntpath = c; + dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *mntpath); + + c = strndup_user(data->client_addr.data, 16); + if (IS_ERR(c)) + return PTR_ERR(c); + *ip_addr = c; + + break; + default: + goto out_bad_version; + } + + return 0; + +out_no_data: + dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n"); + return -EINVAL; + +out_inval_auth: + dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n", + data->auth_flavourlen); + return -EINVAL; + +out_no_address: + dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); + return -EINVAL; + +out_bad_version: + dfprintk(MOUNT, "NFS4: bad nfs_mount_data version %d\n", + data->version); + return -EINVAL; +} + /* * Get the superblock for an NFS4 mountpoint */ @@ -826,68 +909,14 @@ static int nfs4_get_sb(struct file_system_type *fs_type, rpc_authflavor_t authflavour; struct nfs_fh mntfh; struct dentry *mntroot; - char *p, *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; + char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; int error; - if (data == NULL) { - dprintk("%s: missing data argument\n", __FUNCTION__); - return -EINVAL; - } - if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) { - dprintk("%s: bad mount version\n", __FUNCTION__); - return -EINVAL; - } - - /* We now require that the mount process passes the remote address */ - if (data->host_addrlen != sizeof(addr)) - return -EINVAL; - - if (copy_from_user(&addr, data->host_addr, sizeof(addr))) - return -EFAULT; - - if (!nfs_verify_server_address((struct sockaddr *) &addr)) { - dprintk("%s: mount program didn't pass remote IP address!\n", - __FUNCTION__); - return -EINVAL; - } - - /* RFC3530: The default port for NFS is 2049 */ - if (addr.sin_port == 0) - addr.sin_port = htons(NFS_PORT); - - /* Grab the authentication type */ - authflavour = RPC_AUTH_UNIX; - if (data->auth_flavourlen != 0) { - if (data->auth_flavourlen != 1) { - dprintk("%s: Invalid number of RPC auth flavours %d.\n", - __FUNCTION__, data->auth_flavourlen); - error = -EINVAL; - goto out; - } - - if (copy_from_user(&authflavour, data->auth_flavours, - sizeof(authflavour))) { - error = -EFAULT; - goto out; - } - } - - p = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); - if (IS_ERR(p)) - goto out_err; - hostname = p; - - p = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN); - if (IS_ERR(p)) - goto out_err; - mntpath = p; - - dprintk("MNTPATH: %s\n", mntpath); - - p = strndup_user(data->client_addr.data, 16); - if (IS_ERR(p)) - goto out_err; - ip_addr = p; + /* Validate the mount data */ + error = nfs4_validate_mount_data(&data, dev_name, &addr, &authflavour, + &hostname, &mntpath, &ip_addr); + if (error < 0) + goto out; /* Get a volume representation */ server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr, @@ -932,10 +961,6 @@ out: kfree(hostname); return error; -out_err: - error = PTR_ERR(p); - goto out; - out_free: nfs_free_server(server); goto out; -- cgit v1.2.3-70-g09d2 From cce63cd6374e6f1b4ea897ece1454feb13993d7c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:12 -0400 Subject: SUNRPC: Rename rpcb_getport_external routine In preparation for handling NFS mount option parsing in the kernel, rename rpcb_getport_external as rpcb_get_port_sync, and make it available always (instead of only when CONFIG_ROOT_NFS is enabled). Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/nfsroot.c | 2 +- include/linux/sunrpc/clnt.h | 7 ++----- net/sunrpc/rpcb_clnt.c | 21 +++++++++++---------- 3 files changed, 14 insertions(+), 16 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 49d1008ce1d..f0db4703b1c 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -428,7 +428,7 @@ static int __init root_nfs_getport(int program, int version, int proto) printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n", program, version, NIPQUAD(servaddr)); set_sockaddr(&sin, servaddr, 0); - return rpcb_getport_external(&sin, program, version, proto); + return rpcb_getport_sync(&sin, program, version, proto); } diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 097984b0385..b28d919c775 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -120,8 +120,10 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); void rpc_shutdown_client(struct rpc_clnt *); void rpc_release_client(struct rpc_clnt *); + int rpcb_register(u32, u32, int, unsigned short, int *); void rpcb_getport(struct rpc_task *); +int rpcb_getport_sync(struct sockaddr_in *, __u32, __u32, int); void rpc_call_setup(struct rpc_task *, struct rpc_message *, int); @@ -141,10 +143,5 @@ void rpc_force_rebind(struct rpc_clnt *); size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); char * rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); -/* - * Helper function for NFSroot support - */ -int rpcb_getport_external(struct sockaddr_in *, __u32, __u32, int); - #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_CLNT_H */ diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 9a20f380ab0..fc881a675eb 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -12,6 +12,8 @@ * Copyright (C) 1996, Olaf Kirch */ +#include + #include #include #include @@ -247,21 +249,20 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) return error; } -#ifdef CONFIG_ROOT_NFS /** - * rpcb_getport_external - obtain the port for an RPC service on a given host + * rpcb_getport_sync - obtain the port for an RPC service on a given host * @sin: address of remote peer * @prog: RPC program number to bind * @vers: RPC version number to bind * @prot: transport protocol to use to make this request * * Called from outside the RPC client in a synchronous task context. + * Uses default timeout parameters specified by underlying transport. * - * For now, this supports only version 2 queries, but is used only by - * mount_clnt for NFS_ROOT. + * XXX: Needs to support IPv6, and rpcbind versions 3 and 4 */ -int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog, - __u32 vers, int prot) +int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog, + __u32 vers, int prot) { struct rpcbind_args map = { .r_prog = prog, @@ -278,10 +279,10 @@ int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog, char hostname[40]; int status; - dprintk("RPC: rpcb_getport_external(%u.%u.%u.%u, %u, %u, %d)\n", - NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); + dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n", + __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); - sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr)); + sprintf(hostname, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr)); rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0); if (IS_ERR(rpcb_clnt)) return PTR_ERR(rpcb_clnt); @@ -296,7 +297,7 @@ int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog, } return status; } -#endif +EXPORT_SYMBOL_GPL(rpcb_getport_sync); /** * rpcb_getport - obtain the port for a given RPC service on a given host -- cgit v1.2.3-70-g09d2 From 43780b87fa799ae65df11d89d4539d8d6a7c67eb Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:22 -0400 Subject: SUNRPC: Add a convenient default for the hostname when calling rpc_create() A couple of callers just use a stringified IP address for the rpc client's hostname. Move the logic for constructing this into rpc_create(), so it can be shared. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/mount_clnt.c | 13 ++++--------- fs/nfsd/nfs4callback.c | 6 ------ net/sunrpc/clnt.c | 13 +++++++++++++ 3 files changed, 17 insertions(+), 15 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 878d7a5cb6d..2892ec84306 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -28,8 +28,7 @@ #define MOUNT_UMNT 3 */ -static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *, - int, int); +static struct rpc_clnt * mnt_create(struct sockaddr_in *, int, int); static struct rpc_program mnt_program; struct mnt_fhstatus { @@ -52,14 +51,12 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, .rpc_argp = path, .rpc_resp = &result, }; - char hostname[32]; int status; dprintk("NFS: nfs_mount(%08x:%s)\n", (unsigned)ntohl(addr->sin_addr.s_addr), path); - sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr)); - mnt_clnt = mnt_create(hostname, addr, version, protocol); + mnt_clnt = mnt_create(addr, version, protocol); if (IS_ERR(mnt_clnt)) return PTR_ERR(mnt_clnt); @@ -73,15 +70,13 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, return status < 0? status : (result.status? -EACCES : 0); } -static struct rpc_clnt * -mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, - int protocol) +static struct rpc_clnt *mnt_create(struct sockaddr_in *srvaddr, int version, + int protocol) { struct rpc_create_args args = { .protocol = protocol, .address = (struct sockaddr *)srvaddr, .addrsize = sizeof(*srvaddr), - .servername = hostname, .program = &mnt_program, .version = version, .authflavor = RPC_AUTH_UNIX, diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 6b1b487db1e..5443c52b57a 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -394,7 +394,6 @@ nfsd4_probe_callback(struct nfs4_client *clp) .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], .rpc_argp = clp, }; - char clientname[16]; int status; if (atomic_read(&cb->cb_set)) @@ -417,11 +416,6 @@ nfsd4_probe_callback(struct nfs4_client *clp) memset(program->stats, 0, sizeof(cb->cb_stat)); program->stats->program = program; - /* Just here to make some printk's more useful: */ - snprintf(clientname, sizeof(clientname), - "%u.%u.%u.%u", NIPQUAD(addr.sin_addr)); - args.servername = clientname; - /* Create RPC client */ cb->cb_client = rpc_create(&args); if (IS_ERR(cb->cb_client)) { diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e1553cf2a68..0d9b5275fac 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -234,12 +234,25 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) { struct rpc_xprt *xprt; struct rpc_clnt *clnt; + char servername[20]; xprt = xprt_create_transport(args->protocol, args->address, args->addrsize, args->timeout); if (IS_ERR(xprt)) return (struct rpc_clnt *)xprt; + /* + * If the caller chooses not to specify a hostname, whip + * up a string representation of the passed-in address. + */ + if (args->servername == NULL) { + struct sockaddr_in *addr = + (struct sockaddr_in *) &args->address; + snprintf(servername, sizeof(servername), NIPQUAD_FMT, + NIPQUAD(addr->sin_addr.s_addr)); + args->servername = servername; + } + /* * By default, kernel RPC client connects from a reserved port. * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters, -- cgit v1.2.3-70-g09d2 From 3ea97309e6b18bce200211b3f9188e8023321adc Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:27 -0400 Subject: NFS: Remake nfsroot_mount as a permanent part of NFS client In preparation for supporting NFSv2 and NFSv3 mount option handling in the kernel NFS client, convert mount_clnt.c to be a permanent part of the NFS client, instead of built only when CONFIG_ROOT_NFS is enabled. In addition, we also replace the "struct sockaddr_in *" argument with something more generic, to help support IPv6 at some later point. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/Makefile | 4 ++-- fs/nfs/mount_clnt.c | 55 +++++++++++++++++++++++++------------------------- fs/nfs/nfsroot.c | 3 ++- include/linux/nfs_fs.h | 5 ++--- 4 files changed, 34 insertions(+), 33 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index f4580b44eef..b55cb236cf7 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -6,8 +6,8 @@ obj-$(CONFIG_NFS_FS) += nfs.o nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ pagelist.o proc.o read.o symlink.o unlink.o \ - write.o namespace.o -nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o + write.o namespace.o mount_clnt.o +nfs-$(CONFIG_ROOT_NFS) += nfsroot.o nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 2892ec84306..ee4899d9662 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -18,7 +18,7 @@ #include #ifdef RPC_DEBUG -# define NFSDBG_FACILITY NFSDBG_ROOT +# define NFSDBG_FACILITY NFSDBG_MOUNT #endif /* @@ -28,7 +28,6 @@ #define MOUNT_UMNT 3 */ -static struct rpc_clnt * mnt_create(struct sockaddr_in *, int, int); static struct rpc_program mnt_program; struct mnt_fhstatus { @@ -36,14 +35,21 @@ struct mnt_fhstatus { struct nfs_fh * fh; }; -/* - * Obtain an NFS file handle for the given host and path +/** + * nfs_mount - Obtain an NFS file handle for the given host and path + * @addr: pointer to server's address + * @len: size of server's address + * @hostname: name of server host, or NULL + * @path: pointer to string containing export path to mount + * @version: mount version to use for this request + * @protocol: transport protocol to use for thie request + * @fh: pointer to location to place returned file handle + * + * Uses default timeout parameters specified by underlying transport. */ -int -nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, - int version, int protocol) +int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path, + int version, int protocol, struct nfs_fh *fh) { - struct rpc_clnt *mnt_clnt; struct mnt_fhstatus result = { .fh = fh }; @@ -51,12 +57,23 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, .rpc_argp = path, .rpc_resp = &result, }; + struct rpc_create_args args = { + .protocol = protocol, + .address = addr, + .addrsize = len, + .servername = hostname, + .program = &mnt_program, + .version = version, + .authflavor = RPC_AUTH_UNIX, + .flags = RPC_CLNT_CREATE_INTR, + }; + struct rpc_clnt *mnt_clnt; int status; - dprintk("NFS: nfs_mount(%08x:%s)\n", - (unsigned)ntohl(addr->sin_addr.s_addr), path); + dprintk("NFS: sending MNT request for %s:%s\n", + (hostname ? hostname : "server"), path); - mnt_clnt = mnt_create(addr, version, protocol); + mnt_clnt = rpc_create(&args); if (IS_ERR(mnt_clnt)) return PTR_ERR(mnt_clnt); @@ -70,22 +87,6 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, return status < 0? status : (result.status? -EACCES : 0); } -static struct rpc_clnt *mnt_create(struct sockaddr_in *srvaddr, int version, - int protocol) -{ - struct rpc_create_args args = { - .protocol = protocol, - .address = (struct sockaddr *)srvaddr, - .addrsize = sizeof(*srvaddr), - .program = &mnt_program, - .version = version, - .authflavor = RPC_AUTH_UNIX, - .flags = RPC_CLNT_CREATE_INTR, - }; - - return rpc_create(&args); -} - /* * XDR encode/decode functions for MOUNT */ diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index f0db4703b1c..3490322d114 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -496,7 +496,8 @@ static int __init root_nfs_get_handle(void) NFS_MNT3_VERSION : NFS_MNT_VERSION; set_sockaddr(&sin, servaddr, htons(mount_port)); - status = nfsroot_mount(&sin, nfs_path, &fh, version, protocol); + status = nfs_mount((struct sockaddr *) &sin, sizeof(sin), NULL, + nfs_path, version, protocol, &fh); if (status < 0) printk(KERN_ERR "Root-NFS: Server returned error %d " "while mounting %s\n", status, nfs_path); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 04f659f1e56..c098ae194f7 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -494,10 +494,9 @@ static inline void nfs3_forget_cached_acls(struct inode *inode) /* * linux/fs/mount_clnt.c - * (Used only by nfsroot module) */ -extern int nfsroot_mount(struct sockaddr_in *, char *, struct nfs_fh *, - int, int); +extern int nfs_mount(struct sockaddr *, size_t, char *, char *, + int, int, struct nfs_fh *); /* * inline functions -- cgit v1.2.3-70-g09d2 From 19207231c9874899e7511507ebb1b88d648a5743 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:33 -0400 Subject: NFS: Clean up in-kernel NFS mount Clean up white space and coding conventions. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/mount_clnt.c | 83 ++++++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 46 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index ee4899d9662..961dc524327 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -1,7 +1,5 @@ /* - * linux/fs/nfs/mount_clnt.c - * - * MOUNT client to support NFSroot. + * In-kernel MOUNT protocol client * * Copyright (C) 1997, Olaf Kirch */ @@ -21,18 +19,11 @@ # define NFSDBG_FACILITY NFSDBG_MOUNT #endif -/* -#define MOUNT_PROGRAM 100005 -#define MOUNT_VERSION 1 -#define MOUNT_MNT 1 -#define MOUNT_UMNT 3 - */ - static struct rpc_program mnt_program; struct mnt_fhstatus { - unsigned int status; - struct nfs_fh * fh; + u32 status; + struct nfs_fh *fh; }; /** @@ -90,8 +81,8 @@ int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path, /* * XDR encode/decode functions for MOUNT */ -static int -xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path) +static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, + const char *path) { p = xdr_encode_string(p, path); @@ -99,8 +90,8 @@ xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path) return 0; } -static int -xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) +static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, + struct mnt_fhstatus *res) { struct nfs_fh *fh = res->fh; @@ -111,8 +102,8 @@ xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) return 0; } -static int -xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) +static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, + struct mnt_fhstatus *res) { struct nfs_fh *fh = res->fh; @@ -131,53 +122,53 @@ xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) #define MNT_fhstatus_sz (1 + 8) #define MNT_fhstatus3_sz (1 + 16) -static struct rpc_procinfo mnt_procedures[] = { -[MNTPROC_MNT] = { - .p_proc = MNTPROC_MNT, - .p_encode = (kxdrproc_t) xdr_encode_dirpath, - .p_decode = (kxdrproc_t) xdr_decode_fhstatus, - .p_arglen = MNT_dirpath_sz, - .p_replen = MNT_fhstatus_sz, - .p_statidx = MNTPROC_MNT, - .p_name = "MOUNT", +static struct rpc_procinfo mnt_procedures[] = { + [MNTPROC_MNT] = { + .p_proc = MNTPROC_MNT, + .p_encode = (kxdrproc_t) xdr_encode_dirpath, + .p_decode = (kxdrproc_t) xdr_decode_fhstatus, + .p_arglen = MNT_dirpath_sz, + .p_replen = MNT_fhstatus_sz, + .p_statidx = MNTPROC_MNT, + .p_name = "MOUNT", }, }; static struct rpc_procinfo mnt3_procedures[] = { -[MOUNTPROC3_MNT] = { - .p_proc = MOUNTPROC3_MNT, - .p_encode = (kxdrproc_t) xdr_encode_dirpath, - .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, - .p_arglen = MNT_dirpath_sz, - .p_replen = MNT_fhstatus3_sz, - .p_statidx = MOUNTPROC3_MNT, - .p_name = "MOUNT", + [MOUNTPROC3_MNT] = { + .p_proc = MOUNTPROC3_MNT, + .p_encode = (kxdrproc_t) xdr_encode_dirpath, + .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, + .p_arglen = MNT_dirpath_sz, + .p_replen = MNT_fhstatus3_sz, + .p_statidx = MOUNTPROC3_MNT, + .p_name = "MOUNT", }, }; -static struct rpc_version mnt_version1 = { - .number = 1, - .nrprocs = 2, - .procs = mnt_procedures +static struct rpc_version mnt_version1 = { + .number = 1, + .nrprocs = 2, + .procs = mnt_procedures, }; -static struct rpc_version mnt_version3 = { - .number = 3, - .nrprocs = 2, - .procs = mnt3_procedures +static struct rpc_version mnt_version3 = { + .number = 3, + .nrprocs = 2, + .procs = mnt3_procedures, }; -static struct rpc_version * mnt_version[] = { +static struct rpc_version *mnt_version[] = { NULL, &mnt_version1, NULL, &mnt_version3, }; -static struct rpc_stat mnt_stats; +static struct rpc_stat mnt_stats; -static struct rpc_program mnt_program = { +static struct rpc_program mnt_program = { .name = "mount", .number = NFS_MNT_PROGRAM, .nrvers = ARRAY_SIZE(mnt_version), -- cgit v1.2.3-70-g09d2 From 013a8c1ab5a214c608e12b602770449fb6b15a81 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:38 -0400 Subject: NFS: Improve debugging output in NFS in-kernel mount client Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/mount_clnt.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 961dc524327..8afd9f7e7a9 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -66,7 +66,7 @@ int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path, mnt_clnt = rpc_create(&args); if (IS_ERR(mnt_clnt)) - return PTR_ERR(mnt_clnt); + goto out_clnt_err; if (version == NFS_MNT3_VERSION) msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; @@ -75,7 +75,31 @@ int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path, status = rpc_call_sync(mnt_clnt, &msg, 0); rpc_shutdown_client(mnt_clnt); - return status < 0? status : (result.status? -EACCES : 0); + + if (status < 0) + goto out_call_err; + if (result.status != 0) + goto out_mnt_err; + + dprintk("NFS: MNT request succeeded\n"); + status = 0; + +out: + return status; + +out_clnt_err: + status = PTR_ERR(mnt_clnt); + dprintk("NFS: failed to create RPC client, status=%d\n", status); + goto out; + +out_call_err: + dprintk("NFS: failed to start MNT request, status=%d\n", status); + goto out; + +out_mnt_err: + dprintk("NFS: MNT server returned result %d\n", result.status); + status = -EACCES; + goto out; } /* -- cgit v1.2.3-70-g09d2 From bf0fd7680f1cf31b9cbabcc037a204548e2c866d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:44 -0400 Subject: NFS: Add enums and match tables for mount option parsing This generic infrastructure works for both NFS and NFSv4 mounts. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 528 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 528 insertions(+) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ed3ec4477a0..7e56411e55f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,164 @@ #define NFSDBG_FACILITY NFSDBG_VFS + +struct nfs_parsed_mount_data { + int flags; + int rsize, wsize; + int timeo, retrans; + int acregmin, acregmax, + acdirmin, acdirmax; + int namlen; + unsigned int bsize; + unsigned int auth_flavor_len; + rpc_authflavor_t auth_flavors[1]; + char *client_address; + + struct { + struct sockaddr_in address; + unsigned int program; + unsigned int version; + unsigned short port; + int protocol; + } mount_server; + + struct { + struct sockaddr_in address; + char *hostname; + char *export_path; + unsigned int program; + int protocol; + } nfs_server; +}; + +enum { + /* Mount options that take no arguments */ + Opt_soft, Opt_hard, + Opt_intr, Opt_nointr, + Opt_posix, Opt_noposix, + Opt_cto, Opt_nocto, + Opt_ac, Opt_noac, + Opt_lock, Opt_nolock, + Opt_v2, Opt_v3, + Opt_udp, Opt_tcp, + Opt_acl, Opt_noacl, + Opt_rdirplus, Opt_nordirplus, + + /* Mount options that take integer arguments */ + Opt_port, + Opt_rsize, Opt_wsize, Opt_bsize, + Opt_timeo, Opt_retrans, + Opt_acregmin, Opt_acregmax, + Opt_acdirmin, Opt_acdirmax, + Opt_actimeo, + Opt_namelen, + Opt_mountport, + Opt_mountprog, Opt_mountvers, + Opt_nfsprog, Opt_nfsvers, + + /* Mount options that take string arguments */ + Opt_sec, Opt_proto, Opt_mountproto, + Opt_addr, Opt_mounthost, Opt_clientaddr, + + /* Mount options that are ignored */ + Opt_userspace, Opt_deprecated, + + Opt_err +}; + +static match_table_t nfs_mount_option_tokens = { + { Opt_userspace, "bg" }, + { Opt_userspace, "fg" }, + { Opt_soft, "soft" }, + { Opt_hard, "hard" }, + { Opt_intr, "intr" }, + { Opt_nointr, "nointr" }, + { Opt_posix, "posix" }, + { Opt_noposix, "noposix" }, + { Opt_cto, "cto" }, + { Opt_nocto, "nocto" }, + { Opt_ac, "ac" }, + { Opt_noac, "noac" }, + { Opt_lock, "lock" }, + { Opt_nolock, "nolock" }, + { Opt_v2, "v2" }, + { Opt_v3, "v3" }, + { Opt_udp, "udp" }, + { Opt_tcp, "tcp" }, + { Opt_acl, "acl" }, + { Opt_noacl, "noacl" }, + { Opt_rdirplus, "rdirplus" }, + { Opt_nordirplus, "nordirplus" }, + + { Opt_port, "port=%u" }, + { Opt_rsize, "rsize=%u" }, + { Opt_wsize, "wsize=%u" }, + { Opt_bsize, "bsize=%u" }, + { Opt_timeo, "timeo=%u" }, + { Opt_retrans, "retrans=%u" }, + { Opt_acregmin, "acregmin=%u" }, + { Opt_acregmax, "acregmax=%u" }, + { Opt_acdirmin, "acdirmin=%u" }, + { Opt_acdirmax, "acdirmax=%u" }, + { Opt_actimeo, "actimeo=%u" }, + { Opt_userspace, "retry=%u" }, + { Opt_namelen, "namlen=%u" }, + { Opt_mountport, "mountport=%u" }, + { Opt_mountprog, "mountprog=%u" }, + { Opt_mountvers, "mountvers=%u" }, + { Opt_nfsprog, "nfsprog=%u" }, + { Opt_nfsvers, "nfsvers=%u" }, + { Opt_nfsvers, "vers=%u" }, + + { Opt_sec, "sec=%s" }, + { Opt_proto, "proto=%s" }, + { Opt_mountproto, "mountproto=%s" }, + { Opt_addr, "addr=%s" }, + { Opt_clientaddr, "clientaddr=%s" }, + { Opt_mounthost, "mounthost=%s" }, + + { Opt_err, NULL } +}; + +enum { + Opt_xprt_udp, Opt_xprt_tcp, + + Opt_xprt_err +}; + +static match_table_t nfs_xprt_protocol_tokens = { + { Opt_xprt_udp, "udp" }, + { Opt_xprt_tcp, "tcp" }, + + { Opt_xprt_err, NULL } +}; + +enum { + Opt_sec_none, Opt_sec_sys, + Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p, + Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp, + Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp, + + Opt_sec_err +}; + +static match_table_t nfs_secflavor_tokens = { + { Opt_sec_none, "none" }, + { Opt_sec_none, "null" }, + { Opt_sec_sys, "sys" }, + + { Opt_sec_krb5, "krb5" }, + { Opt_sec_krb5i, "krb5i" }, + { Opt_sec_krb5p, "krb5p" }, + + { Opt_sec_lkey, "lkey" }, + { Opt_sec_lkeyi, "lkeyi" }, + { Opt_sec_lkeyp, "lkeyp" }, + + { Opt_sec_err, NULL } +}; + + static void nfs_umount_begin(struct vfsmount *, int); static int nfs_statfs(struct dentry *, struct kstatfs *); static int nfs_show_options(struct seq_file *, struct vfsmount *); @@ -463,6 +622,375 @@ static int nfs_verify_server_address(struct sockaddr *addr) return 0; } +/* + * Error-check and convert a string of mount options from user space into + * a data structure + */ +static int nfs_parse_mount_options(char *raw, + struct nfs_parsed_mount_data *mnt) +{ + char *p, *string; + + if (!raw) { + dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); + return 1; + } + dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw); + + while ((p = strsep(&raw, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + int option, token; + + if (!*p) + continue; + + dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", p); + + token = match_token(p, nfs_mount_option_tokens, args); + switch (token) { + case Opt_soft: + mnt->flags |= NFS_MOUNT_SOFT; + break; + case Opt_hard: + mnt->flags &= ~NFS_MOUNT_SOFT; + break; + case Opt_intr: + mnt->flags |= NFS_MOUNT_INTR; + break; + case Opt_nointr: + mnt->flags &= ~NFS_MOUNT_INTR; + break; + case Opt_posix: + mnt->flags |= NFS_MOUNT_POSIX; + break; + case Opt_noposix: + mnt->flags &= ~NFS_MOUNT_POSIX; + break; + case Opt_cto: + mnt->flags &= ~NFS_MOUNT_NOCTO; + break; + case Opt_nocto: + mnt->flags |= NFS_MOUNT_NOCTO; + break; + case Opt_ac: + mnt->flags &= ~NFS_MOUNT_NOAC; + break; + case Opt_noac: + mnt->flags |= NFS_MOUNT_NOAC; + break; + case Opt_lock: + mnt->flags &= ~NFS_MOUNT_NONLM; + break; + case Opt_nolock: + mnt->flags |= NFS_MOUNT_NONLM; + break; + case Opt_v2: + mnt->flags &= ~NFS_MOUNT_VER3; + break; + case Opt_v3: + mnt->flags |= NFS_MOUNT_VER3; + break; + case Opt_udp: + mnt->flags &= ~NFS_MOUNT_TCP; + mnt->nfs_server.protocol = IPPROTO_UDP; + mnt->timeo = 7; + mnt->retrans = 5; + break; + case Opt_tcp: + mnt->flags |= NFS_MOUNT_TCP; + mnt->nfs_server.protocol = IPPROTO_TCP; + mnt->timeo = 600; + mnt->retrans = 2; + break; + case Opt_acl: + mnt->flags &= ~NFS_MOUNT_NOACL; + break; + case Opt_noacl: + mnt->flags |= NFS_MOUNT_NOACL; + break; + case Opt_rdirplus: + mnt->flags &= ~NFS_MOUNT_NORDIRPLUS; + break; + case Opt_nordirplus: + mnt->flags |= NFS_MOUNT_NORDIRPLUS; + break; + + case Opt_port: + if (match_int(args, &option)) + return 0; + if (option < 0 || option > 65535) + return 0; + mnt->nfs_server.address.sin_port = htonl(option); + break; + case Opt_rsize: + if (match_int(args, &mnt->rsize)) + return 0; + break; + case Opt_wsize: + if (match_int(args, &mnt->wsize)) + return 0; + break; + case Opt_bsize: + if (match_int(args, &option)) + return 0; + if (option < 0) + return 0; + mnt->bsize = option; + break; + case Opt_timeo: + if (match_int(args, &mnt->timeo)) + return 0; + break; + case Opt_retrans: + if (match_int(args, &mnt->retrans)) + return 0; + break; + case Opt_acregmin: + if (match_int(args, &mnt->acregmin)) + return 0; + break; + case Opt_acregmax: + if (match_int(args, &mnt->acregmax)) + return 0; + break; + case Opt_acdirmin: + if (match_int(args, &mnt->acdirmin)) + return 0; + break; + case Opt_acdirmax: + if (match_int(args, &mnt->acdirmax)) + return 0; + break; + case Opt_actimeo: + if (match_int(args, &option)) + return 0; + if (option < 0) + return 0; + mnt->acregmin = + mnt->acregmax = + mnt->acdirmin = + mnt->acdirmax = option; + break; + case Opt_namelen: + if (match_int(args, &mnt->namlen)) + return 0; + break; + case Opt_mountport: + if (match_int(args, &option)) + return 0; + if (option < 0 || option > 65535) + return 0; + mnt->mount_server.port = option; + break; + case Opt_mountprog: + if (match_int(args, &option)) + return 0; + if (option < 0) + return 0; + mnt->mount_server.program = option; + break; + case Opt_mountvers: + if (match_int(args, &option)) + return 0; + if (option < 0) + return 0; + mnt->mount_server.version = option; + break; + case Opt_nfsprog: + if (match_int(args, &option)) + return 0; + if (option < 0) + return 0; + mnt->nfs_server.program = option; + break; + case Opt_nfsvers: + if (match_int(args, &option)) + return 0; + switch (option) { + case 2: + mnt->flags &= ~NFS_MOUNT_VER3; + break; + case 3: + mnt->flags |= NFS_MOUNT_VER3; + break; + default: + goto out_unrec_vers; + } + break; + + case Opt_sec: + string = match_strdup(args); + if (string == NULL) + goto out_nomem; + token = match_token(string, nfs_secflavor_tokens, args); + kfree(string); + + /* + * The flags setting is for v2/v3. The flavor_len + * setting is for v4. v2/v3 also need to know the + * difference between NULL and UNIX. + */ + switch (token) { + case Opt_sec_none: + mnt->flags &= ~NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 0; + mnt->auth_flavors[0] = RPC_AUTH_NULL; + break; + case Opt_sec_sys: + mnt->flags &= ~NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 0; + mnt->auth_flavors[0] = RPC_AUTH_UNIX; + break; + case Opt_sec_krb5: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; + break; + case Opt_sec_krb5i: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; + break; + case Opt_sec_krb5p: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; + break; + case Opt_sec_lkey: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; + break; + case Opt_sec_lkeyi: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; + break; + case Opt_sec_lkeyp: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; + break; + case Opt_sec_spkm: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; + break; + case Opt_sec_spkmi: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; + break; + case Opt_sec_spkmp: + mnt->flags |= NFS_MOUNT_SECFLAVOUR; + mnt->auth_flavor_len = 1; + mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; + break; + default: + goto out_unrec_sec; + } + break; + case Opt_proto: + string = match_strdup(args); + if (string == NULL) + goto out_nomem; + token = match_token(string, + nfs_xprt_protocol_tokens, args); + kfree(string); + + switch (token) { + case Opt_udp: + mnt->flags &= ~NFS_MOUNT_TCP; + mnt->nfs_server.protocol = IPPROTO_UDP; + mnt->timeo = 7; + mnt->retrans = 5; + break; + case Opt_tcp: + mnt->flags |= NFS_MOUNT_TCP; + mnt->nfs_server.protocol = IPPROTO_TCP; + mnt->timeo = 600; + mnt->retrans = 2; + break; + default: + goto out_unrec_xprt; + } + break; + case Opt_mountproto: + string = match_strdup(args); + if (string == NULL) + goto out_nomem; + token = match_token(string, + nfs_xprt_protocol_tokens, args); + kfree(string); + + switch (token) { + case Opt_udp: + mnt->mount_server.protocol = IPPROTO_UDP; + break; + case Opt_tcp: + mnt->mount_server.protocol = IPPROTO_TCP; + break; + default: + goto out_unrec_xprt; + } + break; + case Opt_addr: + string = match_strdup(args); + if (string == NULL) + goto out_nomem; + mnt->nfs_server.address.sin_family = AF_INET; + mnt->nfs_server.address.sin_addr.s_addr = + in_aton(string); + kfree(string); + break; + case Opt_clientaddr: + string = match_strdup(args); + if (string == NULL) + goto out_nomem; + mnt->client_address = string; + break; + case Opt_mounthost: + string = match_strdup(args); + if (string == NULL) + goto out_nomem; + mnt->mount_server.address.sin_family = AF_INET; + mnt->mount_server.address.sin_addr.s_addr = + in_aton(string); + kfree(string); + break; + + case Opt_userspace: + case Opt_deprecated: + break; + + default: + goto out_unknown; + } + } + + return 1; + +out_nomem: + printk(KERN_INFO "NFS: not enough memory to parse option\n"); + return 0; + +out_unrec_vers: + printk(KERN_INFO "NFS: unrecognized NFS version number\n"); + return 0; + +out_unrec_xprt: + printk(KERN_INFO "NFS: unrecognized transport protocol\n"); + return 0; + +out_unrec_sec: + printk(KERN_INFO "NFS: unrecognized security flavor\n"); + return 0; + +out_unknown: + printk(KERN_INFO "NFS: unknown mount option: %s\n", p); + return 0; +} + /* * Validate the NFS2/NFS3 mount data * - fills in the mount root filehandle -- cgit v1.2.3-70-g09d2 From 0076d7b7bab580ca2e94637d351fa7cd357743a8 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:49 -0400 Subject: NFS: Introduce generic mount client API For NFSv2 and v3 mounts, the first step is to contact the server's MOUNTD and request the file handle for the root of the mounted share. Add a function to the NFS client that handles this operation. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 7e56411e55f..48db52a7067 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -991,6 +991,63 @@ out_unknown: return 0; } +/* + * Use the remote server's MOUNT service to request the NFS file handle + * corresponding to the provided path. + */ +static int nfs_try_mount(struct nfs_parsed_mount_data *args, + struct nfs_fh *root_fh) +{ + struct sockaddr_in sin; + int status; + + if (args->mount_server.version == 0) { + if (args->flags & NFS_MOUNT_VER3) + args->mount_server.version = NFS_MNT3_VERSION; + else + args->mount_server.version = NFS_MNT_VERSION; + } + + /* + * Construct the mount server's address. + */ + if (args->mount_server.address.sin_addr.s_addr != INADDR_ANY) + sin = args->mount_server.address; + else + sin = args->nfs_server.address; + if (args->mount_server.port == 0) { + status = rpcb_getport_sync(&sin, + args->mount_server.program, + args->mount_server.version, + args->mount_server.protocol); + if (status < 0) + goto out_err; + sin.sin_port = htons(status); + } else + sin.sin_port = htons(args->mount_server.port); + + /* + * Now ask the mount server to map our export path + * to a file handle. + */ + status = nfs_mount((struct sockaddr *) &sin, + sizeof(sin), + args->nfs_server.hostname, + args->nfs_server.export_path, + args->mount_server.version, + args->mount_server.protocol, + root_fh); + if (status < 0) + goto out_err; + + return status; + +out_err: + dfprintk(MOUNT, "NFS: unable to contact server on host " + NIPQUAD_FMT "\n", NIPQUAD(sin.sin_addr.s_addr)); + return status; +} + /* * Validate the NFS2/NFS3 mount data * - fills in the mount root filehandle -- cgit v1.2.3-70-g09d2 From 136d558ce766967fe3cbf54c3351aba261b5d53b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:54 -0400 Subject: NFS: Add final pieces to support in-kernel mount option parsing Hook in final components required for supporting in-kernel mount option parsing for NFSv2 and NFSv3 mounts. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 10 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 48db52a7067..757aa3b7e64 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1051,10 +1051,28 @@ out_err: /* * Validate the NFS2/NFS3 mount data * - fills in the mount root filehandle + * + * For option strings, user space handles the following behaviors: + * + * + DNS: mapping server host name to IP address ("addr=" option) + * + * + failure mode: how to behave if a mount request can't be handled + * immediately ("fg/bg" option) + * + * + retry: how often to retry a mount request ("retry=" option) + * + * + breaking back: trying proto=udp after proto=tcp, v2 after v3, + * mountproto=tcp after mountproto=udp, and so on + * + * XXX: as far as I can tell, changing the NFS program number is not + * supported in the NFS client. */ -static int nfs_validate_mount_data(struct nfs_mount_data *data, - struct nfs_fh *mntfh) +static int nfs_validate_mount_data(struct nfs_mount_data **options, + struct nfs_fh *mntfh, + const char *dev_name) { + struct nfs_mount_data *data = *options; + if (data == NULL) goto out_no_data; @@ -1087,8 +1105,78 @@ static int nfs_validate_mount_data(struct nfs_mount_data *data, memset(mntfh->data + mntfh->size, 0, sizeof(mntfh->data) - mntfh->size); break; - default: - goto out_bad_version; + default: { + unsigned int len; + char *c; + int status; + struct nfs_parsed_mount_data args = { + .flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP), + .rsize = NFS_MAX_FILE_IO_SIZE, + .wsize = NFS_MAX_FILE_IO_SIZE, + .timeo = 600, + .retrans = 2, + .acregmin = 3, + .acregmax = 60, + .acdirmin = 30, + .acdirmax = 60, + .mount_server.protocol = IPPROTO_UDP, + .mount_server.program = NFS_MNT_PROGRAM, + .nfs_server.protocol = IPPROTO_TCP, + .nfs_server.program = NFS_PROGRAM, + }; + + if (nfs_parse_mount_options((char *) *options, &args) == 0) + return -EINVAL; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + /* + * NB: after this point, caller will free "data" + * if we return an error + */ + *options = data; + + c = strchr(dev_name, ':'); + if (c == NULL) + return -EINVAL; + len = c - dev_name - 1; + if (len > sizeof(data->hostname)) + return -EINVAL; + strncpy(data->hostname, dev_name, len); + args.nfs_server.hostname = data->hostname; + + c++; + if (strlen(c) > NFS_MAXPATHLEN) + return -EINVAL; + args.nfs_server.export_path = c; + + status = nfs_try_mount(&args, mntfh); + if (status) + return -EINVAL; + + /* + * Translate to nfs_mount_data, which nfs_fill_super + * can deal with. + */ + data->version = 6; + data->flags = args.flags; + data->rsize = args.rsize; + data->wsize = args.wsize; + data->timeo = args.timeo; + data->retrans = args.retrans; + data->acregmin = args.acregmin; + data->acregmax = args.acregmax; + data->acdirmin = args.acdirmin; + data->acdirmax = args.acdirmax; + data->addr = args.nfs_server.address; + data->namlen = args.namlen; + data->bsize = args.bsize; + data->pseudoflavor = args.auth_flavors[0]; + + break; + } } if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) @@ -1117,11 +1205,6 @@ out_no_sec: dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n"); return -EINVAL; -out_bad_version: - dfprintk(MOUNT, "NFS: bad nfs_mount_data version %d\n", - data->version); - return -EINVAL; - #ifndef CONFIG_NFS_V3 out_v3_not_compiled: dfprintk(MOUNT, "NFS: NFSv3 is not compiled into kernel\n"); @@ -1242,7 +1325,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, int error; /* Validate the mount data */ - error = nfs_validate_mount_data(data, &mntfh); + error = nfs_validate_mount_data(&data, &mntfh, dev_name); if (error < 0) goto out; @@ -1283,6 +1366,8 @@ static int nfs_get_sb(struct file_system_type *fs_type, error = 0; out: + if (data != raw_data) + kfree(data); return error; out_err_nosb: -- cgit v1.2.3-70-g09d2 From 8007122520f0a3599bdc4df47358a5d83b2574aa Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 1 Jul 2007 12:13:59 -0400 Subject: NFS: Add support for mounting NFSv4 file systems with string options Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 91 ++++++++++++++++++++++++++++++++++++++++++---- include/linux/nfs4_mount.h | 2 +- 2 files changed, 85 insertions(+), 8 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 757aa3b7e64..064e69d2fdd 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1541,8 +1541,90 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options, *ip_addr = c; break; - default: - goto out_bad_version; + default: { + unsigned int len; + struct nfs_parsed_mount_data args = { + .rsize = NFS_MAX_FILE_IO_SIZE, + .wsize = NFS_MAX_FILE_IO_SIZE, + .timeo = 600, + .retrans = 2, + .acregmin = 3, + .acregmax = 60, + .acdirmin = 30, + .acdirmax = 60, + .nfs_server.protocol = IPPROTO_TCP, + }; + + if (nfs_parse_mount_options((char *) *options, &args) == 0) + return -EINVAL; + + if (!nfs_verify_server_address((struct sockaddr *) + &args.nfs_server.address)) + return -EINVAL; + *addr = args.nfs_server.address; + + switch (args.auth_flavor_len) { + case 0: + *authflavour = RPC_AUTH_UNIX; + break; + case 1: + *authflavour = (rpc_authflavor_t) args.auth_flavors[0]; + break; + default: + goto out_inval_auth; + } + + /* + * Translate to nfs4_mount_data, which nfs4_fill_super + * can deal with. + */ + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + *options = data; + + data->version = 1; + data->flags = args.flags & NFS4_MOUNT_FLAGMASK; + data->rsize = args.rsize; + data->wsize = args.wsize; + data->timeo = args.timeo; + data->retrans = args.retrans; + data->acregmin = args.acregmin; + data->acregmax = args.acregmax; + data->acdirmin = args.acdirmin; + data->acdirmax = args.acdirmax; + data->proto = args.nfs_server.protocol; + + /* + * Split "dev_name" into "hostname:mntpath". + */ + c = strchr(dev_name, ':'); + if (c == NULL) + return -EINVAL; + /* while calculating len, pretend ':' is '\0' */ + len = c - dev_name; + if (len > NFS4_MAXNAMLEN) + return -EINVAL; + *hostname = kzalloc(len, GFP_KERNEL); + if (*hostname == NULL) + return -ENOMEM; + strncpy(*hostname, dev_name, len - 1); + + c++; /* step over the ':' */ + len = strlen(c); + if (len > NFS4_MAXPATHLEN) + return -EINVAL; + *mntpath = kzalloc(len + 1, GFP_KERNEL); + if (*mntpath == NULL) + return -ENOMEM; + strncpy(*mntpath, c, len); + + dprintk("MNTPATH: %s\n", *mntpath); + + *ip_addr = args.client_address; + + break; + } } return 0; @@ -1559,11 +1641,6 @@ out_inval_auth: out_no_address: dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); return -EINVAL; - -out_bad_version: - dfprintk(MOUNT, "NFS4: bad nfs_mount_data version %d\n", - data->version); - return -EINVAL; } /* diff --git a/include/linux/nfs4_mount.h b/include/linux/nfs4_mount.h index 26b4c83f831..d8d7480e5a4 100644 --- a/include/linux/nfs4_mount.h +++ b/include/linux/nfs4_mount.h @@ -65,6 +65,6 @@ struct nfs4_mount_data { #define NFS4_MOUNT_NOCTO 0x0010 /* 1 */ #define NFS4_MOUNT_NOAC 0x0020 /* 1 */ #define NFS4_MOUNT_STRICTLOCK 0x1000 /* 1 */ -#define NFS4_MOUNT_FLAGMASK 0xFFFF +#define NFS4_MOUNT_FLAGMASK 0x1033 #endif -- cgit v1.2.3-70-g09d2 From 75180df2ed467866ada839fe73cf7cc7d75c0a22 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 16 May 2007 16:53:28 -0400 Subject: NFS: Add the mount option "nosharecache" Prior to David Howell's mount changes in 2.6.18, users who mounted different directories which happened to be from the same filesystem on the server would get different super blocks, and hence could choose different mount options. As long as there were no hard linked files that crossed from one subtree to another, this was quite safe. Post the changes, if the two directories are on the same filesystem (have the same 'fsid'), they will share the same super block, and hence the same mount options. Add a flag to allow users to elect not to share the NFS super block with another mount point, even if the fsids are the same. This will allow users to set different mount options for the two different super blocks, as was previously possible. It is still up to the user to ensure that there are no cache coherency issues when doing this, however the default behaviour will be to share super blocks whenever two paths result in the same fsid. Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 43 ++++++++++++++++++++++++++++++++++++++----- include/linux/nfs4_mount.h | 3 ++- include/linux/nfs_mount.h | 1 + 3 files changed, 41 insertions(+), 6 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 064e69d2fdd..1b555cd41e3 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -100,6 +100,7 @@ enum { Opt_udp, Opt_tcp, Opt_acl, Opt_noacl, Opt_rdirplus, Opt_nordirplus, + Opt_sharecache, Opt_nosharecache, /* Mount options that take integer arguments */ Opt_port, @@ -146,6 +147,8 @@ static match_table_t nfs_mount_option_tokens = { { Opt_noacl, "noacl" }, { Opt_rdirplus, "rdirplus" }, { Opt_nordirplus, "nordirplus" }, + { Opt_sharecache, "sharecache" }, + { Opt_nosharecache, "nosharecache" }, { Opt_port, "port=%u" }, { Opt_rsize, "rsize=%u" }, @@ -450,6 +453,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, { NFS_MOUNT_NONLM, ",nolock", "" }, { NFS_MOUNT_NOACL, ",noacl", "" }, { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" }, + { NFS_MOUNT_UNSHARED, ",nosharecache", ""}, { 0, NULL, NULL } }; const struct proc_nfs_info *nfs_infop; @@ -714,6 +718,12 @@ static int nfs_parse_mount_options(char *raw, case Opt_nordirplus: mnt->flags |= NFS_MOUNT_NORDIRPLUS; break; + case Opt_sharecache: + mnt->flags &= ~NFS_MOUNT_UNSHARED; + break; + case Opt_nosharecache: + mnt->flags |= NFS_MOUNT_UNSHARED; + break; case Opt_port: if (match_int(args, &option)) @@ -1309,6 +1319,9 @@ static int nfs_compare_super(struct super_block *sb, void *data) if (old->nfs_client != server->nfs_client) return 0; + /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ + if (old->flags & NFS_MOUNT_UNSHARED) + return 0; if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) return 0; return 1; @@ -1322,6 +1335,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, struct nfs_fh mntfh; struct nfs_mount_data *data = raw_data; struct dentry *mntroot; + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; int error; /* Validate the mount data */ @@ -1336,8 +1350,11 @@ static int nfs_get_sb(struct file_system_type *fs_type, goto out; } + if (server->flags & NFS_MOUNT_UNSHARED) + compare_super = NULL; + /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(fs_type, nfs_compare_super, nfs_set_super, server); + s = sget(fs_type, compare_super, nfs_set_super, server); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_err_nosb; @@ -1402,6 +1419,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, struct super_block *s; struct nfs_server *server; struct dentry *mntroot; + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; int error; dprintk("--> nfs_xdev_get_sb()\n"); @@ -1413,8 +1431,11 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, goto out_err_noserver; } + if (server->flags & NFS_MOUNT_UNSHARED) + compare_super = NULL; + /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); + s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_err_nosb; @@ -1657,6 +1678,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, struct nfs_fh mntfh; struct dentry *mntroot; char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; int error; /* Validate the mount data */ @@ -1673,8 +1695,11 @@ static int nfs4_get_sb(struct file_system_type *fs_type, goto out; } + if (server->flags & NFS4_MOUNT_UNSHARED) + compare_super = NULL; + /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(fs_type, nfs_compare_super, nfs_set_super, server); + s = sget(fs_type, compare_super, nfs_set_super, server); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_free; @@ -1740,6 +1765,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, struct super_block *s; struct nfs_server *server; struct dentry *mntroot; + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; int error; dprintk("--> nfs4_xdev_get_sb()\n"); @@ -1751,8 +1777,11 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, goto out_err_noserver; } + if (server->flags & NFS4_MOUNT_UNSHARED) + compare_super = NULL; + /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); + s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_err_nosb; @@ -1807,6 +1836,7 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, struct nfs_server *server; struct dentry *mntroot; struct nfs_fh mntfh; + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; int error; dprintk("--> nfs4_referral_get_sb()\n"); @@ -1818,8 +1848,11 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, goto out_err_noserver; } + if (server->flags & NFS4_MOUNT_UNSHARED) + compare_super = NULL; + /* Get a superblock - note that we may end up sharing one that already exists */ - s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); + s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_err_nosb; diff --git a/include/linux/nfs4_mount.h b/include/linux/nfs4_mount.h index d8d7480e5a4..a0dcf665565 100644 --- a/include/linux/nfs4_mount.h +++ b/include/linux/nfs4_mount.h @@ -65,6 +65,7 @@ struct nfs4_mount_data { #define NFS4_MOUNT_NOCTO 0x0010 /* 1 */ #define NFS4_MOUNT_NOAC 0x0020 /* 1 */ #define NFS4_MOUNT_STRICTLOCK 0x1000 /* 1 */ -#define NFS4_MOUNT_FLAGMASK 0x1033 +#define NFS4_MOUNT_UNSHARED 0x8000 /* 1 */ +#define NFS4_MOUNT_FLAGMASK 0x9033 #endif diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h index 0b82a17c705..a3ade89a64d 100644 --- a/include/linux/nfs_mount.h +++ b/include/linux/nfs_mount.h @@ -62,6 +62,7 @@ struct nfs_mount_data { #define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ #define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */ +#define NFS_MOUNT_UNSHARED 0x8000 /* 5 */ #define NFS_MOUNT_FLAGMASK 0xFFFF #endif -- cgit v1.2.3-70-g09d2 From 275a5d24bf56b2d9dd4644c54a56366b89a028f1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 16 May 2007 16:53:28 -0400 Subject: NFS: Error when mounting the same filesystem with different options Unless the user sets the NFS_MOUNT_NOSHAREDCACHE mount flag, we should return EBUSY if the filesystem is already mounted on a superblock that has set conflicting mount options. Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 1b555cd41e3..a2b1af89ca1 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1317,7 +1317,9 @@ static int nfs_compare_super(struct super_block *sb, void *data) { struct nfs_server *server = data, *old = NFS_SB(sb); - if (old->nfs_client != server->nfs_client) + if (memcmp(&old->nfs_client->cl_addr, + &server->nfs_client->cl_addr, + sizeof(old->nfs_client->cl_addr)) != 0) return 0; /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ if (old->flags & NFS_MOUNT_UNSHARED) @@ -1327,6 +1329,39 @@ static int nfs_compare_super(struct super_block *sb, void *data) return 1; } +#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS) + +static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) +{ + const struct nfs_server *a = s->s_fs_info; + const struct rpc_clnt *clnt_a = a->client; + const struct rpc_clnt *clnt_b = b->client; + + if ((s->s_flags & NFS_MS_MASK) != (flags & NFS_MS_MASK)) + goto Ebusy; + if (a->nfs_client != b->nfs_client) + goto Ebusy; + if (a->flags != b->flags) + goto Ebusy; + if (a->wsize != b->wsize) + goto Ebusy; + if (a->rsize != b->rsize) + goto Ebusy; + if (a->acregmin != b->acregmin) + goto Ebusy; + if (a->acregmax != b->acregmax) + goto Ebusy; + if (a->acdirmin != b->acdirmin) + goto Ebusy; + if (a->acdirmax != b->acdirmax) + goto Ebusy; + if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor) + goto Ebusy; + return 0; +Ebusy: + return -EBUSY; +} + static int nfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) { @@ -1361,8 +1396,11 @@ static int nfs_get_sb(struct file_system_type *fs_type, } if (s->s_fs_info != server) { + error = nfs_compare_mount_options(s, server, flags); nfs_free_server(server); server = NULL; + if (error < 0) + goto error_splat_super; } if (!s->s_root) { @@ -1442,8 +1480,11 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, } if (s->s_fs_info != server) { + error = nfs_compare_mount_options(s, server, flags); nfs_free_server(server); server = NULL; + if (error < 0) + goto error_splat_super; } if (!s->s_root) { -- cgit v1.2.3-70-g09d2 From 6f2e64d3e1f661095e274c9d9d47e3f39a6cf1c0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 6 Jul 2007 10:53:21 -0400 Subject: NFSv4: Make the NFS state model work with the nosharedcache mount option Consider the case where the user has mounted the remote filesystem server:/foo on the two local directories /bar and /baz using the nosharedcache mount option. The files /bar/file and /baz/file are represented by different inodes in the local namespace, but refer to the same file /foo/file on the server. Consider the case where a process opens both /bar/file and /baz/file, then closes /bar/file: because the nfs4_state is not shared between /bar/file and /baz/file, the kernel will see that the nfs4_state for /bar/file is no longer referenced, so it will send off a CLOSE rpc call. Unless the open_owners differ, then that CLOSE call will invalidate the open state on /baz/file too. Conclusion: we cannot share open state owners between two different non-shared mount instances of the same filesystem. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4state.c | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index dd1aa2b598c..6c028e734fe 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -83,6 +83,7 @@ struct nfs_unique_id { struct nfs4_state_owner { struct nfs_unique_id so_owner_id; struct nfs_client *so_client; + struct nfs_server *so_server; struct rb_node so_client_node; struct rpc_cred *so_cred; /* Associated cred */ diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 523cc2cbb5e..e9662ba81d8 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -156,8 +156,9 @@ static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id) } static struct nfs4_state_owner * -nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred) +nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred) { + struct nfs_client *clp = server->nfs_client; struct rb_node **p = &clp->cl_state_owners.rb_node, *parent = NULL; struct nfs4_state_owner *sp, *res = NULL; @@ -166,6 +167,14 @@ nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred) parent = *p; sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); + if (server < sp->so_server) { + p = &parent->rb_left; + continue; + } + if (server > sp->so_server) { + p = &parent->rb_right; + continue; + } if (cred < sp->so_cred) p = &parent->rb_left; else if (cred > sp->so_cred) @@ -190,6 +199,14 @@ nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new) parent = *p; sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); + if (new->so_server < sp->so_server) { + p = &parent->rb_left; + continue; + } + if (new->so_server > sp->so_server) { + p = &parent->rb_right; + continue; + } if (new->so_cred < sp->so_cred) p = &parent->rb_left; else if (new->so_cred > sp->so_cred) @@ -260,7 +277,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct struct nfs4_state_owner *sp, *new; spin_lock(&clp->cl_lock); - sp = nfs4_find_state_owner(clp, cred); + sp = nfs4_find_state_owner(server, cred); spin_unlock(&clp->cl_lock); if (sp != NULL) return sp; @@ -268,6 +285,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct if (new == NULL) return NULL; new->so_client = clp; + new->so_server = server; new->so_cred = cred; spin_lock(&clp->cl_lock); sp = nfs4_insert_state_owner(clp, new); -- cgit v1.2.3-70-g09d2 From 137d6acaa64afa4cf3d977417424e731ea04705a Mon Sep 17 00:00:00 2001 From: Frank Filz Date: Mon, 9 Jul 2007 15:32:29 -0700 Subject: NFSv4: Make sure unlock is really an unlock when cancelling a lock I ran into a curious issue when a lock is being canceled. The cancellation results in a lock request to the vfs layer instead of an unlock request. This is particularly insidious when the process that owns the lock is exiting. In that case, sometimes the erroneous lock is applied AFTER the process has entered zombie state, preventing the lock from ever being released. Eventually other processes block on the lock causing a slow degredation of the system. In the 2.6.16 kernel this was investigated on, the problem is compounded by the fact that the cl_sem is held while blocking on the vfs lock, which results in most processes accessing the nfs file system in question hanging. In more detail, here is how the situation occurs: first _nfs4_do_setlk(): static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int reclaim) ... ret = nfs4_wait_for_completion_rpc_task(task); if (ret == 0) { ... } else data->cancelled = 1; then nfs4_lock_release(): static void nfs4_lock_release(void *calldata) ... if (data->cancelled != 0) { struct rpc_task *task; task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, data->arg.lock_seqid); The problem is the same file_lock that was passed in to _nfs4_do_setlk() gets passed to nfs4_do_unlck() from nfs4_lock_release(). So the type is still F_RDLCK or FWRLCK, not F_UNLCK. At some point, when cancelling the lock, the type needs to be changed to F_UNLCK. It seemed easiest to do that in nfs4_do_unlck(), but it could be done in nfs4_lock_release(). The concern I had with doing it there was if something still needed the original file_lock, though it turns out the original file_lock still needs to be modified by nfs4_do_unlck() because nfs4_do_unlck() uses the original file_lock to pass to the vfs layer, and a copy of the original file_lock for the RPC request. It seems like the simplest solution is to force all situations where nfs4_do_unlck() is being used to result in an unlock, so with that in mind, I made the following change: Signed-off-by: Frank Filz Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ba86ec654c2..fee2da856c9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3275,6 +3275,11 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, { struct nfs4_unlockdata *data; + /* Ensure this is an unlock - when canceling a lock, the + * canceled lock is passed in, and it won't be an unlock. + */ + fl->fl_type = F_UNLCK; + data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); if (data == NULL) { nfs_free_seqid(seqid); -- cgit v1.2.3-70-g09d2 From 259902ea951008bcbd31a49f667062ff8012ef55 Mon Sep 17 00:00:00 2001 From: Pavel Emelianov Date: Sun, 15 Jul 2007 23:39:56 -0700 Subject: Make NFS client use seq_list_xxx helpers This includes /proc/fs/nfsfs/servers and /proc/fs/nfsfs/volumes entries. Both need to show the header and use the list_head. Signed-off-by: Pavel Emelianov Acked-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/client.c | 54 ++++++------------------------------------------------ 1 file changed, 6 insertions(+), 48 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index ccb455053ee..a49f9feff77 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1206,23 +1206,9 @@ static int nfs_server_list_open(struct inode *inode, struct file *file) */ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) { - struct list_head *_p; - loff_t pos = *_pos; - /* lock the list against modification */ spin_lock(&nfs_client_lock); - - /* allow for the header line */ - if (!pos) - return SEQ_START_TOKEN; - pos--; - - /* find the n'th element in the list */ - list_for_each(_p, &nfs_client_list) - if (!pos--) - break; - - return _p != &nfs_client_list ? _p : NULL; + return seq_list_start_head(&nfs_client_list, *_pos); } /* @@ -1230,14 +1216,7 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) */ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) { - struct list_head *_p; - - (*pos)++; - - _p = v; - _p = (v == SEQ_START_TOKEN) ? nfs_client_list.next : _p->next; - - return _p != &nfs_client_list ? _p : NULL; + return seq_list_next(v, &nfs_client_list, pos); } /* @@ -1256,7 +1235,7 @@ static int nfs_server_list_show(struct seq_file *m, void *v) struct nfs_client *clp; /* display header on line 1 */ - if (v == SEQ_START_TOKEN) { + if (v == &nfs_client_list) { seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); return 0; } @@ -1297,23 +1276,9 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file) */ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) { - struct list_head *_p; - loff_t pos = *_pos; - /* lock the list against modification */ spin_lock(&nfs_client_lock); - - /* allow for the header line */ - if (!pos) - return SEQ_START_TOKEN; - pos--; - - /* find the n'th element in the list */ - list_for_each(_p, &nfs_volume_list) - if (!pos--) - break; - - return _p != &nfs_volume_list ? _p : NULL; + return seq_list_start_head(&nfs_volume_list, *_pos); } /* @@ -1321,14 +1286,7 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) */ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) { - struct list_head *_p; - - (*pos)++; - - _p = v; - _p = (v == SEQ_START_TOKEN) ? nfs_volume_list.next : _p->next; - - return _p != &nfs_volume_list ? _p : NULL; + return seq_list_next(v, &nfs_volume_list, pos); } /* @@ -1349,7 +1307,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) char dev[8], fsid[17]; /* display header on line 1 */ - if (v == SEQ_START_TOKEN) { + if (v == &nfs_volume_list) { seq_puts(m, "NV SERVER PORT DEV FSID\n"); return 0; } -- cgit v1.2.3-70-g09d2 From 8e1f936b73150f5095448a0fee6d4f30a1f9001d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 17 Jul 2007 04:03:17 -0700 Subject: mm: clean up and kernelify shrinker registration I can never remember what the function to register to receive VM pressure is called. I have to trace down from __alloc_pages() to find it. It's called "set_shrinker()", and it needs Your Help. 1) Don't hide struct shrinker. It contains no magic. 2) Don't allocate "struct shrinker". It's not helpful. 3) Call them "register_shrinker" and "unregister_shrinker". 4) Call the function "shrink" not "shrinker". 5) Reduce the 17 lines of waffly comments to 13, but document it properly. Signed-off-by: Rusty Russell Cc: David Chinner Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dcache.c | 7 ++++++- fs/dquot.c | 7 ++++++- fs/inode.c | 7 ++++++- fs/mbcache.c | 9 ++++++--- fs/nfs/super.c | 10 ++++++---- fs/xfs/linux-2.6/xfs_buf.c | 14 ++++++-------- fs/xfs/quota/xfs_qm.c | 10 +++++++--- include/linux/mm.h | 38 +++++++++++++++++++++----------------- mm/vmscan.c | 42 +++++++++++------------------------------- net/sunrpc/auth.c | 11 ++++++----- 10 files changed, 81 insertions(+), 74 deletions(-) (limited to 'fs/nfs') diff --git a/fs/dcache.c b/fs/dcache.c index 0e73aa0a0e8..cb9d05056b5 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -883,6 +883,11 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask) return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; } +static struct shrinker dcache_shrinker = { + .shrink = shrink_dcache_memory, + .seeks = DEFAULT_SEEKS, +}; + /** * d_alloc - allocate a dcache entry * @parent: parent of entry to allocate @@ -2115,7 +2120,7 @@ static void __init dcache_init(unsigned long mempages) dentry_cache = KMEM_CACHE(dentry, SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD); - set_shrinker(DEFAULT_SEEKS, shrink_dcache_memory); + register_shrinker(&dcache_shrinker); /* Hash may have been set up in dcache_init_early */ if (!hashdist) diff --git a/fs/dquot.c b/fs/dquot.c index 8819d281500..7e273151f58 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -538,6 +538,11 @@ static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) return (dqstats.free_dquots / 100) * sysctl_vfs_cache_pressure; } +static struct shrinker dqcache_shrinker = { + .shrink = shrink_dqcache_memory, + .seeks = DEFAULT_SEEKS, +}; + /* * Put reference to dquot * NOTE: If you change this function please check whether dqput_blocks() works right... @@ -1870,7 +1875,7 @@ static int __init dquot_init(void) printk("Dquot-cache hash table entries: %ld (order %ld, %ld bytes)\n", nr_hash, order, (PAGE_SIZE << order)); - set_shrinker(DEFAULT_SEEKS, shrink_dqcache_memory); + register_shrinker(&dqcache_shrinker); return 0; } diff --git a/fs/inode.c b/fs/inode.c index 47b87b071de..320e088d0b2 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -462,6 +462,11 @@ static int shrink_icache_memory(int nr, gfp_t gfp_mask) return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; } +static struct shrinker icache_shrinker = { + .shrink = shrink_icache_memory, + .seeks = DEFAULT_SEEKS, +}; + static void __wait_on_freeing_inode(struct inode *inode); /* * Called with the inode lock held. @@ -1385,7 +1390,7 @@ void __init inode_init(unsigned long mempages) SLAB_MEM_SPREAD), init_once, NULL); - set_shrinker(DEFAULT_SEEKS, shrink_icache_memory); + register_shrinker(&icache_shrinker); /* Hash may have been set up in inode_init_early */ if (!hashdist) diff --git a/fs/mbcache.c b/fs/mbcache.c index deeb9dc062d..fbb1d02f879 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -100,7 +100,6 @@ struct mb_cache { static LIST_HEAD(mb_cache_list); static LIST_HEAD(mb_cache_lru_list); static DEFINE_SPINLOCK(mb_cache_spinlock); -static struct shrinker *mb_shrinker; static inline int mb_cache_indexes(struct mb_cache *cache) @@ -118,6 +117,10 @@ mb_cache_indexes(struct mb_cache *cache) static int mb_cache_shrink_fn(int nr_to_scan, gfp_t gfp_mask); +static struct shrinker mb_cache_shrinker = { + .shrink = mb_cache_shrink_fn, + .seeks = DEFAULT_SEEKS, +}; static inline int __mb_cache_entry_is_hashed(struct mb_cache_entry *ce) @@ -662,13 +665,13 @@ mb_cache_entry_find_next(struct mb_cache_entry *prev, int index, static int __init init_mbcache(void) { - mb_shrinker = set_shrinker(DEFAULT_SEEKS, mb_cache_shrink_fn); + register_shrinker(&mb_cache_shrinker); return 0; } static void __exit exit_mbcache(void) { - remove_shrinker(mb_shrinker); + unregister_shrinker(&mb_cache_shrinker); } module_init(init_mbcache) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index a2b1af89ca1..adffe1615c5 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -300,7 +300,10 @@ static const struct super_operations nfs4_sops = { }; #endif -static struct shrinker *acl_shrinker; +static struct shrinker acl_shrinker = { + .shrink = nfs_access_cache_shrinker, + .seeks = DEFAULT_SEEKS, +}; /* * Register the NFS filesystems @@ -321,7 +324,7 @@ int __init register_nfs_fs(void) if (ret < 0) goto error_2; #endif - acl_shrinker = set_shrinker(DEFAULT_SEEKS, nfs_access_cache_shrinker); + register_shrinker(&acl_shrinker); return 0; #ifdef CONFIG_NFS_V4 @@ -339,8 +342,7 @@ error_0: */ void __exit unregister_nfs_fs(void) { - if (acl_shrinker != NULL) - remove_shrinker(acl_shrinker); + unregister_shrinker(&acl_shrinker); #ifdef CONFIG_NFS_V4 unregister_filesystem(&nfs4_fs_type); nfs_unregister_sysctl(); diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 2df63622354..b0f0e58866d 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -35,10 +35,13 @@ #include static kmem_zone_t *xfs_buf_zone; -static struct shrinker *xfs_buf_shake; STATIC int xfsbufd(void *); STATIC int xfsbufd_wakeup(int, gfp_t); STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int); +static struct shrinker xfs_buf_shake = { + .shrink = xfsbufd_wakeup, + .seeks = DEFAULT_SEEKS, +}; static struct workqueue_struct *xfslogd_workqueue; struct workqueue_struct *xfsdatad_workqueue; @@ -1832,14 +1835,9 @@ xfs_buf_init(void) if (!xfsdatad_workqueue) goto out_destroy_xfslogd_workqueue; - xfs_buf_shake = set_shrinker(DEFAULT_SEEKS, xfsbufd_wakeup); - if (!xfs_buf_shake) - goto out_destroy_xfsdatad_workqueue; - + register_shrinker(&xfs_buf_shake); return 0; - out_destroy_xfsdatad_workqueue: - destroy_workqueue(xfsdatad_workqueue); out_destroy_xfslogd_workqueue: destroy_workqueue(xfslogd_workqueue); out_free_buf_zone: @@ -1854,7 +1852,7 @@ xfs_buf_init(void) void xfs_buf_terminate(void) { - remove_shrinker(xfs_buf_shake); + unregister_shrinker(&xfs_buf_shake); destroy_workqueue(xfsdatad_workqueue); destroy_workqueue(xfslogd_workqueue); kmem_zone_destroy(xfs_buf_zone); diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 7def4c69934..2d274b23ade 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -62,7 +62,6 @@ uint ndquot; kmem_zone_t *qm_dqzone; kmem_zone_t *qm_dqtrxzone; -static struct shrinker *xfs_qm_shaker; static cred_t xfs_zerocr; @@ -78,6 +77,11 @@ STATIC int xfs_qm_init_quotainos(xfs_mount_t *); STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); STATIC int xfs_qm_shake(int, gfp_t); +static struct shrinker xfs_qm_shaker = { + .shrink = xfs_qm_shake, + .seeks = DEFAULT_SEEKS, +}; + #ifdef DEBUG extern mutex_t qcheck_lock; #endif @@ -149,7 +153,7 @@ xfs_Gqm_init(void) } else xqm->qm_dqzone = qm_dqzone; - xfs_qm_shaker = set_shrinker(DEFAULT_SEEKS, xfs_qm_shake); + register_shrinker(&xfs_qm_shaker); /* * The t_dqinfo portion of transactions. @@ -181,7 +185,7 @@ xfs_qm_destroy( ASSERT(xqm != NULL); ASSERT(xqm->qm_nrefs == 0); - remove_shrinker(xfs_qm_shaker); + unregister_shrinker(&xfs_qm_shaker); hsize = xqm->qm_dqhashmask + 1; for (i = 0; i < hsize; i++) { xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); diff --git a/include/linux/mm.h b/include/linux/mm.h index 97d0cddfd22..4c482a3ee87 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -810,27 +810,31 @@ extern unsigned long do_mremap(unsigned long addr, unsigned long flags, unsigned long new_addr); /* - * Prototype to add a shrinker callback for ageable caches. - * - * These functions are passed a count `nr_to_scan' and a gfpmask. They should - * scan `nr_to_scan' objects, attempting to free them. + * A callback you can register to apply pressure to ageable caches. * - * The callback must return the number of objects which remain in the cache. + * 'shrink' is passed a count 'nr_to_scan' and a 'gfpmask'. It should + * look through the least-recently-used 'nr_to_scan' entries and + * attempt to free them up. It should return the number of objects + * which remain in the cache. If it returns -1, it means it cannot do + * any scanning at this time (eg. there is a risk of deadlock). * - * The callback will be passed nr_to_scan == 0 when the VM is querying the - * cache size, so a fastpath for that case is appropriate. - */ -typedef int (*shrinker_t)(int nr_to_scan, gfp_t gfp_mask); - -/* - * Add an aging callback. The int is the number of 'seeks' it takes - * to recreate one of the objects that these functions age. + * The 'gfpmask' refers to the allocation we are currently trying to + * fulfil. + * + * Note that 'shrink' will be passed nr_to_scan == 0 when the VM is + * querying the cache size, so a fastpath for that case is appropriate. */ +struct shrinker { + int (*shrink)(int nr_to_scan, gfp_t gfp_mask); + int seeks; /* seeks to recreate an obj */ -#define DEFAULT_SEEKS 2 -struct shrinker; -extern struct shrinker *set_shrinker(int, shrinker_t); -extern void remove_shrinker(struct shrinker *shrinker); + /* These are for internal use */ + struct list_head list; + long nr; /* objs pending delete */ +}; +#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */ +extern void register_shrinker(struct shrinker *); +extern void unregister_shrinker(struct shrinker *); /* * Some shared mappigns will want the pages marked read-only diff --git a/mm/vmscan.c b/mm/vmscan.c index 1d9971d8924..2225b7c9df8 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -70,17 +70,6 @@ struct scan_control { int order; }; -/* - * The list of shrinker callbacks used by to apply pressure to - * ageable caches. - */ -struct shrinker { - shrinker_t shrinker; - struct list_head list; - int seeks; /* seeks to recreate an obj */ - long nr; /* objs pending delete */ -}; - #define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru)) #ifdef ARCH_HAS_PREFETCH @@ -123,34 +112,25 @@ static DECLARE_RWSEM(shrinker_rwsem); /* * Add a shrinker callback to be called from the vm */ -struct shrinker *set_shrinker(int seeks, shrinker_t theshrinker) +void register_shrinker(struct shrinker *shrinker) { - struct shrinker *shrinker; - - shrinker = kmalloc(sizeof(*shrinker), GFP_KERNEL); - if (shrinker) { - shrinker->shrinker = theshrinker; - shrinker->seeks = seeks; - shrinker->nr = 0; - down_write(&shrinker_rwsem); - list_add_tail(&shrinker->list, &shrinker_list); - up_write(&shrinker_rwsem); - } - return shrinker; + shrinker->nr = 0; + down_write(&shrinker_rwsem); + list_add_tail(&shrinker->list, &shrinker_list); + up_write(&shrinker_rwsem); } -EXPORT_SYMBOL(set_shrinker); +EXPORT_SYMBOL(register_shrinker); /* * Remove one */ -void remove_shrinker(struct shrinker *shrinker) +void unregister_shrinker(struct shrinker *shrinker) { down_write(&shrinker_rwsem); list_del(&shrinker->list); up_write(&shrinker_rwsem); - kfree(shrinker); } -EXPORT_SYMBOL(remove_shrinker); +EXPORT_SYMBOL(unregister_shrinker); #define SHRINK_BATCH 128 /* @@ -187,7 +167,7 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask, list_for_each_entry(shrinker, &shrinker_list, list) { unsigned long long delta; unsigned long total_scan; - unsigned long max_pass = (*shrinker->shrinker)(0, gfp_mask); + unsigned long max_pass = (*shrinker->shrink)(0, gfp_mask); delta = (4 * scanned) / shrinker->seeks; delta *= max_pass; @@ -215,8 +195,8 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask, int shrink_ret; int nr_before; - nr_before = (*shrinker->shrinker)(0, gfp_mask); - shrink_ret = (*shrinker->shrinker)(this_scan, gfp_mask); + nr_before = (*shrinker->shrink)(0, gfp_mask); + shrink_ret = (*shrinker->shrink)(this_scan, gfp_mask); if (shrink_ret == -1) break; if (shrink_ret < nr_before) diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index aa55d0a03e6..29a8ecc6092 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -543,17 +543,18 @@ rpcauth_uptodatecred(struct rpc_task *task) test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; } - -static struct shrinker *rpc_cred_shrinker; +static struct shrinker rpc_cred_shrinker = { + .shrink = rpcauth_cache_shrinker, + .seeks = DEFAULT_SEEKS, +}; void __init rpcauth_init_module(void) { rpc_init_authunix(); - rpc_cred_shrinker = set_shrinker(DEFAULT_SEEKS, rpcauth_cache_shrinker); + register_shrinker(&rpc_cred_shrinker); } void __exit rpcauth_remove_module(void) { - if (rpc_cred_shrinker != NULL) - remove_shrinker(rpc_cred_shrinker); + unregister_shrinker(&rpc_cred_shrinker); } -- cgit v1.2.3-70-g09d2 From 831441862956fffa17b9801db37e6ea1650b0f69 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 17 Jul 2007 04:03:35 -0700 Subject: Freezer: make kernel threads nonfreezable by default Currently, the freezer treats all tasks as freezable, except for the kernel threads that explicitly set the PF_NOFREEZE flag for themselves. This approach is problematic, since it requires every kernel thread to either set PF_NOFREEZE explicitly, or call try_to_freeze(), even if it doesn't care for the freezing of tasks at all. It seems better to only require the kernel threads that want to or need to be frozen to use some freezer-related code and to remove any freezer-related code from the other (nonfreezable) kernel threads, which is done in this patch. The patch causes all kernel threads to be nonfreezable by default (ie. to have PF_NOFREEZE set by default) and introduces the set_freezable() function that should be called by the freezable kernel threads in order to unset PF_NOFREEZE. It also makes all of the currently freezable kernel threads call set_freezable(), so it shouldn't cause any (intentional) change of behaviour to appear. Additionally, it updates documentation to describe the freezing of tasks more accurately. [akpm@linux-foundation.org: build fixes] Signed-off-by: Rafael J. Wysocki Acked-by: Nigel Cunningham Cc: Pavel Machek Cc: Oleg Nesterov Cc: Gautham R Shenoy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/power/freezing-of-tasks.txt | 160 ++++++++++++++++++++++++++++++ Documentation/power/kernel_threads.txt | 40 -------- Documentation/power/swsusp.txt | 18 +--- arch/i386/kernel/apm.c | 2 +- arch/i386/kernel/io_apic.c | 1 + drivers/block/loop.c | 8 +- drivers/block/pktcdvd.c | 1 + drivers/char/apm-emulation.c | 12 +-- drivers/char/hvc_console.c | 1 + drivers/edac/edac_mc.c | 1 + drivers/ieee1394/ieee1394_core.c | 3 +- drivers/ieee1394/nodemgr.c | 1 + drivers/input/gameport/gameport.c | 1 + drivers/input/serio/serio.c | 1 + drivers/input/touchscreen/ucb1400_ts.c | 1 + drivers/macintosh/therm_adt746x.c | 1 + drivers/macintosh/windfarm_core.c | 1 + drivers/md/md.c | 1 - drivers/media/dvb/dvb-core/dvb_frontend.c | 1 + drivers/media/video/cx88/cx88-tvaudio.c | 1 + drivers/media/video/msp3400-kthreads.c | 6 +- drivers/media/video/tvaudio.c | 2 +- drivers/media/video/video-buf-dvb.c | 1 + drivers/media/video/vivi.c | 1 + drivers/mfd/ucb1x00-ts.c | 1 + drivers/mmc/card/queue.c | 7 +- drivers/mtd/mtd_blkdevs.c | 3 +- drivers/mtd/ubi/wl.c | 1 + drivers/net/wireless/airo.c | 3 +- drivers/net/wireless/libertas/main.c | 1 + drivers/pcmcia/cs.c | 1 + drivers/pnp/pnpbios/core.c | 1 + drivers/scsi/libsas/sas_scsi_host.c | 3 +- drivers/scsi/scsi_error.c | 3 +- drivers/usb/atm/ueagle-atm.c | 1 + drivers/usb/core/hub.c | 1 + drivers/usb/gadget/file_storage.c | 3 + drivers/usb/storage/usb.c | 3 +- drivers/video/ps3fb.c | 1 + drivers/w1/w1.c | 1 + fs/cifs/cifsfs.c | 1 + fs/cifs/connect.c | 1 + fs/jffs2/background.c | 1 + fs/lockd/svc.c | 2 + fs/nfs/callback.c | 2 + fs/nfsd/nfssvc.c | 2 + fs/xfs/linux-2.6/xfs_super.c | 1 + include/linux/freezer.h | 14 +++ init/do_mounts_initrd.c | 7 +- kernel/audit.c | 1 + kernel/exit.c | 6 ++ kernel/fork.c | 2 +- kernel/rcutorture.c | 4 +- kernel/rtmutex-tester.c | 1 + kernel/sched.c | 3 - kernel/softirq.c | 3 +- kernel/softlockup.c | 2 +- kernel/workqueue.c | 4 +- mm/pdflush.c | 1 + mm/vmscan.c | 1 + net/bluetooth/bnep/core.c | 2 +- net/bluetooth/cmtp/core.c | 2 +- net/bluetooth/hidp/core.c | 2 +- net/bluetooth/rfcomm/core.c | 2 +- net/core/pktgen.c | 2 + 65 files changed, 256 insertions(+), 113 deletions(-) create mode 100644 Documentation/power/freezing-of-tasks.txt delete mode 100644 Documentation/power/kernel_threads.txt (limited to 'fs/nfs') diff --git a/Documentation/power/freezing-of-tasks.txt b/Documentation/power/freezing-of-tasks.txt new file mode 100644 index 00000000000..af1a282c71a --- /dev/null +++ b/Documentation/power/freezing-of-tasks.txt @@ -0,0 +1,160 @@ +Freezing of tasks + (C) 2007 Rafael J. Wysocki , GPL + +I. What is the freezing of tasks? + +The freezing of tasks is a mechanism by which user space processes and some +kernel threads are controlled during hibernation or system-wide suspend (on some +architectures). + +II. How does it work? + +There are four per-task flags used for that, PF_NOFREEZE, PF_FROZEN, TIF_FREEZE +and PF_FREEZER_SKIP (the last one is auxiliary). The tasks that have +PF_NOFREEZE unset (all user space processes and some kernel threads) are +regarded as 'freezable' and treated in a special way before the system enters a +suspend state as well as before a hibernation image is created (in what follows +we only consider hibernation, but the description also applies to suspend). + +Namely, as the first step of the hibernation procedure the function +freeze_processes() (defined in kernel/power/process.c) is called. It executes +try_to_freeze_tasks() that sets TIF_FREEZE for all of the freezable tasks and +sends a fake signal to each of them. A task that receives such a signal and has +TIF_FREEZE set, should react to it by calling the refrigerator() function +(defined in kernel/power/process.c), which sets the task's PF_FROZEN flag, +changes its state to TASK_UNINTERRUPTIBLE and makes it loop until PF_FROZEN is +cleared for it. Then, we say that the task is 'frozen' and therefore the set of +functions handling this mechanism is called 'the freezer' (these functions are +defined in kernel/power/process.c and include/linux/freezer.h). User space +processes are generally frozen before kernel threads. + +It is not recommended to call refrigerator() directly. Instead, it is +recommended to use the try_to_freeze() function (defined in +include/linux/freezer.h), that checks the task's TIF_FREEZE flag and makes the +task enter refrigerator() if the flag is set. + +For user space processes try_to_freeze() is called automatically from the +signal-handling code, but the freezable kernel threads need to call it +explicitly in suitable places. The code to do this may look like the following: + + do { + hub_events(); + wait_event_interruptible(khubd_wait, + !list_empty(&hub_event_list)); + try_to_freeze(); + } while (!signal_pending(current)); + +(from drivers/usb/core/hub.c::hub_thread()). + +If a freezable kernel thread fails to call try_to_freeze() after the freezer has +set TIF_FREEZE for it, the freezing of tasks will fail and the entire +hibernation operation will be cancelled. For this reason, freezable kernel +threads must call try_to_freeze() somewhere. + +After the system memory state has been restored from a hibernation image and +devices have been reinitialized, the function thaw_processes() is called in +order to clear the PF_FROZEN flag for each frozen task. Then, the tasks that +have been frozen leave refrigerator() and continue running. + +III. Which kernel threads are freezable? + +Kernel threads are not freezable by default. However, a kernel thread may clear +PF_NOFREEZE for itself by calling set_freezable() (the resetting of PF_NOFREEZE +directly is strongly discouraged). From this point it is regarded as freezable +and must call try_to_freeze() in a suitable place. + +IV. Why do we do that? + +Generally speaking, there is a couple of reasons to use the freezing of tasks: + +1. The principal reason is to prevent filesystems from being damaged after +hibernation. At the moment we have no simple means of checkpointing +filesystems, so if there are any modifications made to filesystem data and/or +metadata on disks, we cannot bring them back to the state from before the +modifications. At the same time each hibernation image contains some +filesystem-related information that must be consistent with the state of the +on-disk data and metadata after the system memory state has been restored from +the image (otherwise the filesystems will be damaged in a nasty way, usually +making them almost impossible to repair). We therefore freeze tasks that might +cause the on-disk filesystems' data and metadata to be modified after the +hibernation image has been created and before the system is finally powered off. +The majority of these are user space processes, but if any of the kernel threads +may cause something like this to happen, they have to be freezable. + +2. The second reason is to prevent user space processes and some kernel threads +from interfering with the suspending and resuming of devices. A user space +process running on a second CPU while we are suspending devices may, for +example, be troublesome and without the freezing of tasks we would need some +safeguards against race conditions that might occur in such a case. + +Although Linus Torvalds doesn't like the freezing of tasks, he said this in one +of the discussions on LKML (http://lkml.org/lkml/2007/4/27/608): + +"RJW:> Why we freeze tasks at all or why we freeze kernel threads? + +Linus: In many ways, 'at all'. + +I _do_ realize the IO request queue issues, and that we cannot actually do +s2ram with some devices in the middle of a DMA. So we want to be able to +avoid *that*, there's no question about that. And I suspect that stopping +user threads and then waiting for a sync is practically one of the easier +ways to do so. + +So in practice, the 'at all' may become a 'why freeze kernel threads?' and +freezing user threads I don't find really objectionable." + +Still, there are kernel threads that may want to be freezable. For example, if +a kernel that belongs to a device driver accesses the device directly, it in +principle needs to know when the device is suspended, so that it doesn't try to +access it at that time. However, if the kernel thread is freezable, it will be +frozen before the driver's .suspend() callback is executed and it will be +thawed after the driver's .resume() callback has run, so it won't be accessing +the device while it's suspended. + +3. Another reason for freezing tasks is to prevent user space processes from +realizing that hibernation (or suspend) operation takes place. Ideally, user +space processes should not notice that such a system-wide operation has occurred +and should continue running without any problems after the restore (or resume +from suspend). Unfortunately, in the most general case this is quite difficult +to achieve without the freezing of tasks. Consider, for example, a process +that depends on all CPUs being online while it's running. Since we need to +disable nonboot CPUs during the hibernation, if this process is not frozen, it +may notice that the number of CPUs has changed and may start to work incorrectly +because of that. + +V. Are there any problems related to the freezing of tasks? + +Yes, there are. + +First of all, the freezing of kernel threads may be tricky if they depend one +on another. For example, if kernel thread A waits for a completion (in the +TASK_UNINTERRUPTIBLE state) that needs to be done by freezable kernel thread B +and B is frozen in the meantime, then A will be blocked until B is thawed, which +may be undesirable. That's why kernel threads are not freezable by default. + +Second, there are the following two problems related to the freezing of user +space processes: +1. Putting processes into an uninterruptible sleep distorts the load average. +2. Now that we have FUSE, plus the framework for doing device drivers in +userspace, it gets even more complicated because some userspace processes are +now doing the sorts of things that kernel threads do +(https://lists.linux-foundation.org/pipermail/linux-pm/2007-May/012309.html). + +The problem 1. seems to be fixable, although it hasn't been fixed so far. The +other one is more serious, but it seems that we can work around it by using +hibernation (and suspend) notifiers (in that case, though, we won't be able to +avoid the realization by the user space processes that the hibernation is taking +place). + +There are also problems that the freezing of tasks tends to expose, although +they are not directly related to it. For example, if request_firmware() is +called from a device driver's .resume() routine, it will timeout and eventually +fail, because the user land process that should respond to the request is frozen +at this point. So, seemingly, the failure is due to the freezing of tasks. +Suppose, however, that the firmware file is located on a filesystem accessible +only through another device that hasn't been resumed yet. In that case, +request_firmware() will fail regardless of whether or not the freezing of tasks +is used. Consequently, the problem is not really related to the freezing of +tasks, since it generally exists anyway. [The solution to this particular +problem is to keep the firmware in memory after it's loaded for the first time +and upload if from memory to the device whenever necessary.] diff --git a/Documentation/power/kernel_threads.txt b/Documentation/power/kernel_threads.txt deleted file mode 100644 index fb57784986b..00000000000 --- a/Documentation/power/kernel_threads.txt +++ /dev/null @@ -1,40 +0,0 @@ -KERNEL THREADS - - -Freezer - -Upon entering a suspended state the system will freeze all -tasks. This is done by delivering pseudosignals. This affects -kernel threads, too. To successfully freeze a kernel thread -the thread has to check for the pseudosignal and enter the -refrigerator. Code to do this looks like this: - - do { - hub_events(); - wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); - try_to_freeze(); - } while (!signal_pending(current)); - -from drivers/usb/core/hub.c::hub_thread() - - -The Unfreezable - -Some kernel threads however, must not be frozen. The kernel must -be able to finish pending IO operations and later on be able to -write the memory image to disk. Kernel threads needed to do IO -must stay awake. Such threads must mark themselves unfreezable -like this: - - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources. - */ - daemonize("usb-storage"); - - current->flags |= PF_NOFREEZE; - -from drivers/usb/storage/usb.c::usb_stor_control_thread() - -Such drivers are themselves responsible for staying quiet during -the actual snapshotting. diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index 152b510d1bb..aea7e920966 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt @@ -140,21 +140,11 @@ should be sent to the mailing list available through the suspend2 website, and not to the Linux Kernel Mailing List. We are working toward merging suspend2 into the mainline kernel. -Q: A kernel thread must voluntarily freeze itself (call 'refrigerator'). -I found some kernel threads that don't do it, and they don't freeze -so the system can't sleep. Is this a known behavior? - -A: All such kernel threads need to be fixed, one by one. Select the -place where the thread is safe to be frozen (no kernel semaphores -should be held at that point and it must be safe to sleep there), and -add: - - try_to_freeze(); - -If the thread is needed for writing the image to storage, you should -instead set the PF_NOFREEZE process flag when creating the thread (and -be very careful). +Q: What is the freezing of tasks and why are we using it? +A: The freezing of tasks is a mechanism by which user space processes and some +kernel threads are controlled during hibernation or system-wide suspend (on some +architectures). See freezing-of-tasks.txt for details. Q: What is the difference between "platform" and "shutdown"? diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 4112afe712b..47001d50a08 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -222,6 +222,7 @@ #include #include #include +#include #include #include #include @@ -2311,7 +2312,6 @@ static int __init apm_init(void) remove_proc_entry("apm", NULL); return err; } - kapmd_task->flags |= PF_NOFREEZE; wake_up_process(kapmd_task); if (num_online_cpus() > 1 && !smp ) { diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 7f8b7af2b95..21db8f56c9a 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -667,6 +667,7 @@ static int balanced_irq(void *unused) set_pending_irq(i, cpumask_of_cpu(0)); } + set_freezable(); for ( ; ; ) { time_remaining = schedule_timeout_interruptible(time_remaining); try_to_freeze(); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 4503290da40..06eaa11cbc2 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include /* for invalidate_bdev() */ #include @@ -600,13 +601,6 @@ static int loop_thread(void *data) struct loop_device *lo = data; struct bio *bio; - /* - * loop can be used in an encrypted device, - * hence, it mustn't be stopped at all - * because it could be indirectly used during suspension - */ - current->flags |= PF_NOFREEZE; - set_user_nice(current, -20); while (!kthread_should_stop() || lo->lo_bio) { diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 7c294a40002..31be33e4f11 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1593,6 +1593,7 @@ static int kcdrwd(void *foobar) long min_sleep_time, residue; set_user_nice(current, -20); + set_freezable(); for (;;) { DECLARE_WAITQUEUE(wait, current); diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index 179c7a3b6e7..ec116df919d 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -329,13 +330,8 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) /* * Wait for the suspend/resume to complete. If there * are pending acknowledges, we wait here for them. - * - * Note: we need to ensure that the PM subsystem does - * not kick us out of the wait when it suspends the - * threads. */ flags = current->flags; - current->flags |= PF_NOFREEZE; wait_event(apm_suspend_waitqueue, as->suspend_state == SUSPEND_DONE); @@ -365,13 +361,8 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) /* * Wait for the suspend/resume to complete. If there * are pending acknowledges, we wait here for them. - * - * Note: we need to ensure that the PM subsystem does - * not kick us out of the wait when it suspends the - * threads. */ flags = current->flags; - current->flags |= PF_NOFREEZE; wait_event_interruptible(apm_suspend_waitqueue, as->suspend_state == SUSPEND_DONE); @@ -598,7 +589,6 @@ static int __init apm_init(void) kapmd_tsk = NULL; return ret; } - kapmd_tsk->flags |= PF_NOFREEZE; wake_up_process(kapmd_tsk); #ifdef CONFIG_PROC_FS diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index b3ab42e0dd4..83c1151ec7a 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -679,6 +679,7 @@ static int khvcd(void *unused) int poll_mask; struct hvc_struct *hp; + set_freezable(); __set_current_state(TASK_RUNNING); do { poll_mask = 0; diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 7b622300d0e..804875de580 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -1906,6 +1906,7 @@ static void do_edac_check(void) static int edac_kernel_thread(void *arg) { + set_freezable(); while (!kthread_should_stop()) { do_edac_check(); diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 0fc8c6e559e..ee45259573c 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1128,8 +1129,6 @@ static int hpsbpkt_thread(void *__hi) struct list_head tmp; int may_schedule; - current->flags |= PF_NOFREEZE; - while (!kthread_should_stop()) { INIT_LIST_HEAD(&tmp); diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 51a12062ed3..2ffd53461db 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1699,6 +1699,7 @@ static int nodemgr_host_thread(void *__hi) unsigned int g, generation = 0; int i, reset_cycles = 0; + set_freezable(); /* Setup our device-model entries */ nodemgr_create_host_dev_files(host); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index bd686a2a517..20896d5e5f0 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -445,6 +445,7 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent) static int gameport_thread(void *nothing) { + set_freezable(); do { gameport_handle_event(); wait_event_interruptible(gameport_wait, diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index a8f3bc1dff2..372ca493119 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -384,6 +384,7 @@ static struct serio *serio_get_pending_child(struct serio *parent) static int serio_thread(void *nothing) { + set_freezable(); do { serio_handle_event(); wait_event_interruptible(serio_wait, diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index f0cbcdb008e..36f94401915 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -292,6 +292,7 @@ static int ucb1400_ts_thread(void *_ucb) sched_setscheduler(tsk, SCHED_FIFO, ¶m); + set_freezable(); while (!kthread_should_stop()) { unsigned int x, y, p; long timeout; diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index bd55e6ab99f..f25685b9b7c 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -335,6 +335,7 @@ static int monitor_task(void *arg) { struct thermostat* th = arg; + set_freezable(); while(!kthread_should_stop()) { try_to_freeze(); msleep_interruptible(2000); diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 4fcb245ba18..e18d265d5d3 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -92,6 +92,7 @@ static int wf_thread_func(void *data) DBG("wf: thread started\n"); + set_freezable(); while(!kthread_should_stop()) { if (time_after_eq(jiffies, next)) { wf_notify(WF_EVENT_TICK, NULL); diff --git a/drivers/md/md.c b/drivers/md/md.c index 33beaa7da08..9aefc4a023d 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4642,7 +4642,6 @@ static int md_thread(void * arg) * many dirty RAID5 blocks. */ - current->flags |= PF_NOFREEZE; allow_signal(SIGKILL); while (!kthread_should_stop()) { diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index f4e4ca2dcad..b6c7f6610ec 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -523,6 +523,7 @@ static int dvb_frontend_thread(void *data) dvb_frontend_init(fe); + set_freezable(); while (1) { up(&fepriv->sem); /* is locked when we enter the thread... */ restart: diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 259ea08e784..1cc2d286a1c 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -906,6 +906,7 @@ int cx88_audio_thread(void *data) u32 mode = 0; dprintk("cx88: tvaudio thread started\n"); + set_freezable(); for (;;) { msleep_interruptible(1000); if (kthread_should_stop()) diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index e1821eb82fb..d5ee2629121 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -468,6 +469,7 @@ int msp3400c_thread(void *data) v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); + set_freezable(); for (;;) { v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n"); msp_sleep(state, -1); @@ -646,7 +648,7 @@ int msp3410d_thread(void *data) int val, i, std, count; v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); - + set_freezable(); for (;;) { v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); msp_sleep(state,-1); @@ -940,7 +942,7 @@ int msp34xxg_thread(void *data) int val, i; v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); - + set_freezable(); for (;;) { v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n"); msp_sleep(state, -1); diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index c9bf9dbc2ea..9da338dc4f3 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -271,7 +271,7 @@ static int chip_thread(void *data) struct CHIPDESC *desc = chiplist + chip->type; v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name); - + set_freezable(); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (!kthread_should_stop()) diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index fcc5467e763..e617925ba31 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -47,6 +47,7 @@ static int videobuf_dvb_thread(void *data) int err; dprintk("dvb thread started\n"); + set_freezable(); videobuf_read_start(&dvb->dvbq); for (;;) { diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index f7e1d191037..3ef4d0159c3 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -573,6 +573,7 @@ static int vivi_thread(void *data) dprintk(1,"thread started\n"); mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); + set_freezable(); for (;;) { vivi_sleep(dma_q); diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 38e815a2e87..fdbaa776f24 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -209,6 +209,7 @@ static int ucb1x00_thread(void *_ts) DECLARE_WAITQUEUE(wait, tsk); int valid = 0; + set_freezable(); add_wait_queue(&ts->irq_wait, &wait); while (!kthread_should_stop()) { unsigned int x, y, p; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 4fb2089dc69..b53dac8d1b6 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -11,6 +11,7 @@ */ #include #include +#include #include #include @@ -44,11 +45,7 @@ static int mmc_queue_thread(void *d) struct mmc_queue *mq = d; struct request_queue *q = mq->queue; - /* - * Set iothread to ensure that we aren't put to sleep by - * the process freezing. We handle suspension ourselves. - */ - current->flags |= PF_MEMALLOC|PF_NOFREEZE; + current->flags |= PF_MEMALLOC; down(&mq->thread_sem); do { diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 51bc7e2f1f2..ef89780eb9d 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -80,7 +81,7 @@ static int mtd_blktrans_thread(void *arg) struct request_queue *rq = tr->blkcore_priv->rq; /* we might get involved when memory gets low, so use PF_MEMALLOC */ - current->flags |= PF_MEMALLOC | PF_NOFREEZE; + current->flags |= PF_MEMALLOC; spin_lock_irq(rq->queue_lock); while (!kthread_should_stop()) { diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 9ecaf77eca9..ab2174a56bc 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1346,6 +1346,7 @@ static int ubi_thread(void *u) ubi_msg("background thread \"%s\" started, PID %d", ubi->bgt_name, current->pid); + set_freezable(); for (;;) { int err; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 1c54908fdc4..ee1cc14db38 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -3086,7 +3086,8 @@ static int airo_thread(void *data) { struct net_device *dev = data; struct airo_info *ai = dev->priv; int locked; - + + set_freezable(); while(1) { /* make swsusp happy with our thread */ try_to_freeze(); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 4a59306a3f0..9f366242c39 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -613,6 +613,7 @@ static int wlan_service_main_thread(void *data) init_waitqueue_entry(&wait, current); + set_freezable(); for (;;) { lbs_deb_thread( "main-thread 111: intcounter=%d " "currenttxskb=%p dnld_sent=%d\n", diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 50cad3a59a6..7c93a108f9b 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -651,6 +651,7 @@ static int pccardd(void *__skt) add_wait_queue(&skt->thread_wait, &wait); complete(&skt->thread_done); + set_freezable(); for (;;) { unsigned long flags; unsigned int events; diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 3a201b77b96..03baf1c64a2 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -160,6 +160,7 @@ static int pnp_dock_thread(void * unused) { static struct pnp_docking_station_info now; int docked = -1, d = 0; + set_freezable(); while (!unloading) { int status; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index d70ddfda93f..9c5342e7a69 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -40,6 +40,7 @@ #include #include +#include #include /* ---------- SCSI Host glue ---------- */ @@ -868,8 +869,6 @@ static int sas_queue_thread(void *_sas_ha) { struct sas_ha_struct *sas_ha = _sas_ha; - current->flags |= PF_NOFREEZE; - while (1) { set_current_state(TASK_INTERRUPTIBLE); schedule(); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 9adb64ac054..8a525abda30 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1516,8 +1517,6 @@ int scsi_error_handler(void *data) { struct Scsi_Host *shost = data; - current->flags |= PF_NOFREEZE; - /* * We use TASK_INTERRUPTIBLE so that the thread is not * counted against the load average as a running process. diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 4973e147bc7..8f046659b4e 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -1168,6 +1168,7 @@ static int uea_kthread(void *data) struct uea_softc *sc = data; int ret = -EAGAIN; + set_freezable(); uea_enters(INS_TO_USBDEV(sc)); while (!kthread_should_stop()) { if (ret < 0 || sc->reset) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 50e79010401..fd74c50b180 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2728,6 +2728,7 @@ loop: static int hub_thread(void *__unused) { + set_freezable(); do { hub_events(); wait_event_interruptible(khubd_wait, diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 8712ef98717..be7a1bd2823 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3434,6 +3434,9 @@ static int fsg_main_thread(void *fsg_) allow_signal(SIGKILL); allow_signal(SIGUSR1); + /* Allow the thread to be frozen */ + set_freezable(); + /* Arrange for userspace references to be interpreted as kernel * pointers. That way we can pass a kernel pointer to a routine * that expects a __user pointer and it will work okay. */ diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index bef8bcd9bd9..28842d208bb 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -311,8 +311,6 @@ static int usb_stor_control_thread(void * __us) struct Scsi_Host *host = us_to_host(us); int autopm_rc; - current->flags |= PF_NOFREEZE; - for(;;) { US_DEBUGP("*** thread sleeping.\n"); if(down_interruptible(&us->sema)) @@ -920,6 +918,7 @@ static int usb_stor_scan_thread(void * __us) printk(KERN_DEBUG "usb-storage: device found at %d\n", us->pusb_dev->devnum); + set_freezable(); /* Wait for the timeout to expire or for a disconnect */ if (delay_use > 0) { printk(KERN_DEBUG "usb-storage: waiting for device " diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 08b7ffbbbbd..3972aa8cf85 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -812,6 +812,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, static int ps3fbd(void *arg) { + set_freezable(); while (!kthread_should_stop()) { try_to_freeze(); set_current_state(TASK_INTERRUPTIBLE); diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index f5c5b760ed7..c6332108f1c 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -805,6 +805,7 @@ static int w1_control(void *data) struct w1_master *dev, *n; int have_to_wait = 0; + set_freezable(); while (!kthread_should_stop() || have_to_wait) { have_to_wait = 0; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8b0cbf4a4ad..bd0f2f2353c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -849,6 +849,7 @@ static int cifs_oplock_thread(void * dummyarg) __u16 netfid; int rc; + set_freezable(); do { if (try_to_freeze()) continue; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f4e92661b22..0a1b8bd1dfc 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -363,6 +363,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) GFP_KERNEL); } + set_freezable(); while (!kthread_should_stop()) { if (try_to_freeze()) continue; diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 0c82dfcfd24..143c5530caf 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -81,6 +81,7 @@ static int jffs2_garbage_collect_thread(void *_c) set_user_nice(current, 10); + set_freezable(); for (;;) { allow_signal(SIGHUP); diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 26809325469..9fcdef50aad 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -119,6 +120,7 @@ lockd(struct svc_rqst *rqstp) complete(&lockd_start_done); daemonize("lockd"); + set_freezable(); /* Process request with signals blocked, but allow SIGKILL. */ allow_signal(SIGKILL); diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 75f309c8741..a796be5051b 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -67,6 +68,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) daemonize("nfsv4-svc"); /* Process request with signals blocked, but allow SIGKILL. */ allow_signal(SIGKILL); + set_freezable(); complete(&nfs_callback_info.started); diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ff55950efb4..5c8192bcbce 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -432,6 +433,7 @@ nfsd(struct svc_rqst *rqstp) * dirty pages. */ current->flags |= PF_LESS_THROTTLE; + set_freezable(); /* * The main request loop diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 06894cf00b1..4528f9a3f30 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -562,6 +562,7 @@ xfssyncd( bhv_vfs_sync_work_t *work, *n; LIST_HEAD (tmp); + set_freezable(); timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); for (;;) { timeleft = schedule_timeout_interruptible(timeleft); diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 4631086f506..2d38b1a7466 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -1,5 +1,8 @@ /* Freezer declarations */ +#ifndef FREEZER_H_INCLUDED +#define FREEZER_H_INCLUDED + #include #ifdef CONFIG_PM @@ -115,6 +118,14 @@ static inline int freezer_should_skip(struct task_struct *p) return !!(p->flags & PF_FREEZER_SKIP); } +/* + * Tell the freezer that the current task should be frozen by it + */ +static inline void set_freezable(void) +{ + current->flags &= ~PF_NOFREEZE; +} + #else static inline int frozen(struct task_struct *p) { return 0; } static inline int freezing(struct task_struct *p) { return 0; } @@ -130,4 +141,7 @@ static inline int try_to_freeze(void) { return 0; } static inline void freezer_do_not_count(void) {} static inline void freezer_count(void) {} static inline int freezer_should_skip(struct task_struct *p) { return 0; } +static inline void set_freezable(void) {} #endif + +#endif /* FREEZER_H_INCLUDED */ diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index b222ce9e1c8..a6b4c0c08e1 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c @@ -56,12 +56,9 @@ static void __init handle_initrd(void) sys_chroot("."); pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); - if (pid > 0) { - while (pid != sys_wait4(-1, NULL, 0, NULL)) { - try_to_freeze(); + if (pid > 0) + while (pid != sys_wait4(-1, NULL, 0, NULL)) yield(); - } - } /* move initrd to rootfs' /old */ sys_fchdir(old_fd); diff --git a/kernel/audit.c b/kernel/audit.c index 5ce8851facf..eb0f9165b40 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -392,6 +392,7 @@ static int kauditd_thread(void *dummy) { struct sk_buff *skb; + set_freezable(); while (!kthread_should_stop()) { skb = skb_dequeue(&audit_skb_queue); wake_up(&audit_backlog_wait); diff --git a/kernel/exit.c b/kernel/exit.c index 57626692cd9..e8af8d0c248 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -387,6 +388,11 @@ void daemonize(const char *name, ...) * they would be locked into memory. */ exit_mm(current); + /* + * We don't want to have TIF_FREEZE set if the system-wide hibernation + * or suspend transition begins right now. + */ + current->flags |= PF_NOFREEZE; set_special_pids(1, 1); proc_clear_tty(current); diff --git a/kernel/fork.c b/kernel/fork.c index 7c5c5888e00..ba39bdb2a7b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -923,7 +923,7 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p) { unsigned long new_flags = p->flags; - new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE); + new_flags &= ~PF_SUPERPRIV; new_flags |= PF_FORKNOEXEC; if (!(clone_flags & CLONE_PTRACE)) p->ptrace = 0; diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 55ba82a85a6..ddff3324778 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -518,7 +519,6 @@ rcu_torture_writer(void *arg) VERBOSE_PRINTK_STRING("rcu_torture_writer task started"); set_user_nice(current, 19); - current->flags |= PF_NOFREEZE; do { schedule_timeout_uninterruptible(1); @@ -558,7 +558,6 @@ rcu_torture_fakewriter(void *arg) VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started"); set_user_nice(current, 19); - current->flags |= PF_NOFREEZE; do { schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); @@ -589,7 +588,6 @@ rcu_torture_reader(void *arg) VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); set_user_nice(current, 19); - current->flags |= PF_NOFREEZE; do { idx = cur_ops->readlock(); diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c index 015fc633c96..e3055ba6915 100644 --- a/kernel/rtmutex-tester.c +++ b/kernel/rtmutex-tester.c @@ -260,6 +260,7 @@ static int test_func(void *data) int ret; current->flags |= PF_MUTEX_TESTER; + set_freezable(); allow_signal(SIGHUP); for(;;) { diff --git a/kernel/sched.c b/kernel/sched.c index 1c8076676eb..cb31fb4a137 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4912,8 +4912,6 @@ static int migration_thread(void *data) struct migration_req *req; struct list_head *head; - try_to_freeze(); - spin_lock_irq(&rq->lock); if (cpu_is_offline(cpu)) { @@ -5147,7 +5145,6 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) p = kthread_create(migration_thread, hcpu, "migration/%d", cpu); if (IS_ERR(p)) return NOTIFY_BAD; - p->flags |= PF_NOFREEZE; kthread_bind(p, cpu); /* Must be high prio: stop_machine expects to yield to it. */ rq = task_rq_lock(p, &flags); diff --git a/kernel/softirq.c b/kernel/softirq.c index 8de26779016..0f546ddea43 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -488,8 +489,6 @@ void __init softirq_init(void) static int ksoftirqd(void * __bind_cpu) { - current->flags |= PF_NOFREEZE; - set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { diff --git a/kernel/softlockup.c b/kernel/softlockup.c index 0131e296ffb..708d4882c0c 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -116,7 +117,6 @@ static int watchdog(void * __bind_cpu) struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; sched_setscheduler(current, SCHED_FIFO, ¶m); - current->flags |= PF_NOFREEZE; /* initialize timestamp */ touch_softlockup_watchdog(); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index d7d3fa3072e..1935302cc64 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -282,8 +282,8 @@ static int worker_thread(void *__cwq) struct cpu_workqueue_struct *cwq = __cwq; DEFINE_WAIT(wait); - if (!cwq->wq->freezeable) - current->flags |= PF_NOFREEZE; + if (cwq->wq->freezeable) + set_freezable(); set_user_nice(current, -5); diff --git a/mm/pdflush.c b/mm/pdflush.c index 8ce0900dc95..8f6ee073c0e 100644 --- a/mm/pdflush.c +++ b/mm/pdflush.c @@ -92,6 +92,7 @@ struct pdflush_work { static int __pdflush(struct pdflush_work *my_work) { current->flags |= PF_FLUSHER | PF_SWAPWRITE; + set_freezable(); my_work->fn = NULL; my_work->who = current; INIT_LIST_HEAD(&my_work->list); diff --git a/mm/vmscan.c b/mm/vmscan.c index 2225b7c9df8..d419e10e3da 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1421,6 +1421,7 @@ static int kswapd(void *p) * trying to free the first piece of memory in the first place). */ tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; + set_freezable(); order = 0; for ( ; ; ) { diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 1c8f4a0c5f4..1f78c3e336d 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -474,7 +475,6 @@ static int bnep_session(void *arg) daemonize("kbnepd %s", dev->name); set_user_nice(current, -15); - current->flags |= PF_NOFREEZE; init_waitqueue_entry(&wait, current); add_wait_queue(sk->sk_sleep, &wait); diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 66bef1ccee2..ca60a4517fd 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -287,7 +288,6 @@ static int cmtp_session(void *arg) daemonize("kcmtpd_ctr_%d", session->num); set_user_nice(current, -15); - current->flags |= PF_NOFREEZE; init_waitqueue_entry(&wait, current); add_wait_queue(sk->sk_sleep, &wait); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 450eb0244bb..64d89ca2884 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -547,7 +548,6 @@ static int hidp_session(void *arg) daemonize("khidpd_%04x%04x", vendor, product); set_user_nice(current, -15); - current->flags |= PF_NOFREEZE; init_waitqueue_entry(&ctrl_wait, current); init_waitqueue_entry(&intr_wait, current); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 52e04df323e..bb7220770f2 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1940,7 +1941,6 @@ static int rfcomm_run(void *unused) daemonize("krfcommd"); set_user_nice(current, -10); - current->flags |= PF_NOFREEZE; BT_DBG(""); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 75215331b04..bca787fdbc5 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3465,6 +3465,8 @@ static int pktgen_thread_worker(void *arg) set_current_state(TASK_INTERRUPTIBLE); + set_freezable(); + while (!kthread_should_stop()) { pkt_dev = next_to_run(t); -- cgit v1.2.3-70-g09d2 From 370f6599e8bc03fd9fc6d1a1be00ae0c6373ca59 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 8 Jun 2007 15:23:34 -0400 Subject: nfs: disable leases over NFS As Peter Staubach says elsewhere (http://marc.info/?l=linux-kernel&m=118113649526444&w=2): > The problem is that some file system such as NFSv2 and NFSv3 do > not have sufficient support to be able to support leases correctly. > In particular for these two file systems, there is no over the wire > protocol support. > > Currently, these two file systems fail the fcntl(F_SETLEASE) call > accidentally, due to a reference counting difference. These file > systems should fail more consciously, with a proper error to > indicate that the call is invalid for them. Define an nfs setlease method that just returns -EINVAL. If someone can demonstrate a real need, perhaps we could reenable them in the presence of the "nolock" mount option. Signed-off-by: "J. Bruce Fields" Cc: Peter Staubach Cc: Trond Myklebust --- fs/nfs/file.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'fs/nfs') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 8689b736fdd..13ac6fa2b62 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -53,6 +53,7 @@ static int nfs_fsync(struct file *, struct dentry *dentry, int datasync); static int nfs_check_flags(int flags); static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); +static int nfs_setlease(struct file *file, long arg, struct file_lock **fl); const struct file_operations nfs_file_operations = { .llseek = nfs_file_llseek, @@ -69,6 +70,7 @@ const struct file_operations nfs_file_operations = { .flock = nfs_flock, .splice_read = nfs_file_splice_read, .check_flags = nfs_check_flags, + .setlease = nfs_setlease, }; const struct inode_operations nfs_file_inode_operations = { @@ -558,3 +560,13 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) return do_unlk(filp, cmd, fl); return do_setlk(filp, cmd, fl); } + +static int nfs_setlease(struct file *file, long arg, struct file_lock **fl) +{ + /* + * There is no protocol support for leases, so we have no way + * to implement them correctly in the face of opens by other + * clients. + */ + return -EINVAL; +} -- cgit v1.2.3-70-g09d2 From 6d34ac199a4af5c678a3a8f3275aeb2586b72da3 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 11 May 2007 16:09:32 -0400 Subject: locks: make posix_test_lock() interface more consistent Since posix_test_lock(), like fcntl() and ->lock(), indicates absence or presence of a conflict lock by setting fl_type to, respectively, F_UNLCK or something other than F_UNLCK, the return value is no longer needed. Signed-off-by: "J. Bruce Fields" --- fs/locks.c | 10 ++++------ fs/nfs/file.c | 4 +++- include/linux/fs.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'fs/nfs') diff --git a/fs/locks.c b/fs/locks.c index 4c73b857dde..4a8072736ef 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -659,7 +659,7 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w return result; } -int +void posix_test_lock(struct file *filp, struct file_lock *fl) { struct file_lock *cfl; @@ -671,14 +671,12 @@ posix_test_lock(struct file *filp, struct file_lock *fl) if (posix_locks_conflict(cfl, fl)) break; } - if (cfl) { + if (cfl) __locks_copy_lock(fl, cfl); - unlock_kernel(); - return 1; - } else + else fl->fl_type = F_UNLCK; unlock_kernel(); - return 0; + return; } EXPORT_SYMBOL(posix_test_lock); diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 13ac6fa2b62..c87dc713b5d 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -402,7 +402,9 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) lock_kernel(); /* Try local locking first */ - if (posix_test_lock(filp, fl)) { + posix_test_lock(filp, fl); + if (fl->fl_type != F_UNLCK) { + /* found a conflict */ goto out; } diff --git a/include/linux/fs.h b/include/linux/fs.h index b188c2e5338..80deaaf1b74 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -862,7 +862,7 @@ extern void locks_init_lock(struct file_lock *); extern void locks_copy_lock(struct file_lock *, struct file_lock *); extern void locks_remove_posix(struct file *, fl_owner_t); extern void locks_remove_flock(struct file *); -extern int posix_test_lock(struct file *, struct file_lock *); +extern void posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); extern int posix_lock_file_wait(struct file *, struct file_lock *); extern int posix_unblock_lock(struct file *, struct file_lock *); -- cgit v1.2.3-70-g09d2 From 6f220ed5a84d87645a84ae22105dc565f3f248b5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 17 Jul 2007 21:50:45 -0400 Subject: NFSv4: Fix open state recovery Ensure that opendata->state is always initialised when we do state recovery. Ensure that we set the filehandle in the case where we're doing an "OPEN_CLAIM_PREVIOUS" call due to a server reboot. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index fee2da856c9..8799b1d54a0 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -552,6 +552,18 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state * return ERR_PTR(-ENOENT); } +static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state) +{ + struct nfs4_opendata *opendata; + + opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); + if (opendata == NULL) + return ERR_PTR(-ENOMEM); + opendata->state = state; + atomic_inc(&state->count); + return opendata; +} + static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) { struct nfs4_state *newstate; @@ -626,12 +638,11 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state int delegation_type = 0; int status; - opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); - if (opendata == NULL) - return -ENOMEM; + opendata = nfs4_open_recoverdata_alloc(ctx, state); + if (IS_ERR(opendata)) + return PTR_ERR(opendata); opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; opendata->o_arg.fh = NFS_FH(state->inode); - nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh); rcu_read_lock(); delegation = rcu_dereference(NFS_I(state->inode)->delegation); if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) @@ -672,13 +683,12 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) { - struct nfs4_state_owner *sp = state->owner; struct nfs4_opendata *opendata; int ret; - opendata = nfs4_opendata_alloc(&ctx->path, sp, 0, NULL); - if (opendata == NULL) - return -ENOMEM; + opendata = nfs4_open_recoverdata_alloc(ctx, state); + if (IS_ERR(opendata)) + return PTR_ERR(opendata); opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; memcpy(opendata->o_arg.u.delegation.data, stateid->data, sizeof(opendata->o_arg.u.delegation.data)); @@ -823,8 +833,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) /* Update sequence id. */ data->o_arg.id = sp->so_owner_id.id; data->o_arg.clientid = sp->so_client->cl_clientid; - if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) + if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; + nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); + } data->timestamp = jiffies; rpc_call_setup(task, &msg, 0); return; @@ -989,9 +1001,9 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s struct nfs4_opendata *opendata; int ret; - opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); - if (opendata == NULL) - return -ENOMEM; + opendata = nfs4_open_recoverdata_alloc(ctx, state); + if (IS_ERR(opendata)) + return PTR_ERR(opendata); ret = nfs4_open_recover(opendata, state); if (ret == -ESTALE) { /* Invalidate the state owner so we don't ever use it again */ -- cgit v1.2.3-70-g09d2 From 365c8f589afbc27d8cf42d396475017bc1c462fd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 17 Jul 2007 21:52:37 -0400 Subject: NFSv4: Don't fail nfs4_xdr_dec_open if decode_restorefh() failed We can already easily recover from that inside _nfs4_proc_open(). Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index c08738441f7..99a123db108 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4035,7 +4035,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr goto out; if (decode_getfattr(&xdr, res->f_attr, res->server) != 0) goto out; - if ((status = decode_restorefh(&xdr)) != 0) + if (decode_restorefh(&xdr) != 0) goto out; decode_getfattr(&xdr, res->dir_attr, res->server); out: -- cgit v1.2.3-70-g09d2 From 56659e9926ef5996398924c799ecac39ca8b6223 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 17 Jul 2007 21:52:39 -0400 Subject: NFSv4: 'constify' lookup arguments. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 2 +- fs/nfs/nfs4proc.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 6c028e734fe..d2802b1ca3b 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -182,7 +182,7 @@ extern int nfs4_do_close(struct path *path, struct nfs4_state *state); extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); -extern int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name, +extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, struct nfs4_fs_locations *fs_locations, struct page *page); extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8799b1d54a0..5f3689befc2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1565,7 +1565,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, * Note that we'll actually follow the referral later when * we detect fsid mismatch in inode revalidation */ -static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle) +static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle) { int status = -ENOMEM; struct page *page = NULL; @@ -1680,8 +1680,8 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, return status; } -static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, - struct qstr *name, struct nfs_fh *fhandle, +static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh, + const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { int status; @@ -1727,7 +1727,7 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, return err; } -static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, +static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { int status; @@ -3684,7 +3684,7 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) return len; } -int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name, +int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, struct nfs4_fs_locations *fs_locations, struct page *page) { struct nfs_server *server = NFS_SERVER(dir); -- cgit v1.2.3-70-g09d2 From 9936781d0147e13cbc6df02f5265e0b9999ce3cf Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 17 Jul 2007 21:52:41 -0400 Subject: NFSv4: Try to recover from getfh failures in nfs4_xdr_dec_open Try harder to recover the open state if the server failed to return a filehandle. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 7 ++++++- fs/nfs/nfs4xdr.c | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5f3689befc2..7ead63e065a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -66,6 +66,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags); +static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); +static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); /* Prevent leaks of NFSv4 errors into userland */ int nfs4_map_errors(int err) @@ -930,6 +932,9 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) if (status != 0 || !data->rpc_done) return status; + if (o_res->fh.size == 0) + _nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr); + if (o_arg->open_flags & O_CREAT) { update_changeattr(dir, &o_res->cinfo); nfs_post_op_update_inode(dir, o_res->dir_attr); @@ -941,7 +946,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) return status; } if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) - return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); + _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr); return 0; } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 99a123db108..af959147077 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -3161,11 +3161,12 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) uint32_t len; int status; + /* Zero handle first to allow comparisons */ + memset(fh, 0, sizeof(*fh)); + status = decode_op_hdr(xdr, OP_GETFH); if (status) return status; - /* Zero handle first to allow comparisons */ - memset(fh, 0, sizeof(*fh)); READ_BUF(4); READ32(len); @@ -4030,8 +4031,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr status = decode_open(&xdr, res); if (status) goto out; - status = decode_getfh(&xdr, &res->fh); - if (status) + if (decode_getfh(&xdr, &res->fh) != 0) goto out; if (decode_getfattr(&xdr, res->f_attr, res->server) != 0) goto out; -- cgit v1.2.3-70-g09d2 From 9104a55dc382c4aae42dff3f54351085cbcb7317 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 17 Jul 2007 21:52:42 -0400 Subject: NFSv4: More NFSv4 xdr cleanups Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 208 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 134 insertions(+), 74 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index af959147077..5eb92f1e2e1 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -72,10 +72,15 @@ static int nfs4_stat_to_errno(int); */ #define open_owner_id_maxsz (1 + 4) #define lock_owner_id_maxsz (1 + 4) +#define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) #define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) #define compound_decode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) #define op_encode_hdr_maxsz (1) #define op_decode_hdr_maxsz (2) +#define encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE)) +#define decode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE)) +#define encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE)) +#define decode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE)) #define encode_putfh_maxsz (op_encode_hdr_maxsz + 1 + \ (NFS4_FHSIZE >> 2)) #define decode_putfh_maxsz (op_decode_hdr_maxsz) @@ -96,6 +101,11 @@ static int nfs4_stat_to_errno(int); #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ nfs4_fattr_value_maxsz) #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) +#define encode_attrs_maxsz (nfs4_fattr_bitmap_maxsz + \ + 1 + 2 + 1 + \ + nfs4_owner_maxsz + \ + nfs4_group_maxsz + \ + 4 + 4) #define encode_savefh_maxsz (op_encode_hdr_maxsz) #define decode_savefh_maxsz (op_decode_hdr_maxsz) #define encode_restorefh_maxsz (op_encode_hdr_maxsz) @@ -123,7 +133,7 @@ static int nfs4_stat_to_errno(int); #define decode_lookup_maxsz (op_decode_hdr_maxsz) #define encode_share_access_maxsz \ (2) -#define encode_createmode_maxsz (1 + nfs4_fattr_maxsz) +#define encode_createmode_maxsz (1 + encode_attrs_maxsz) #define encode_opentype_maxsz (1 + encode_createmode_maxsz) #define encode_claim_null_maxsz (1 + nfs4_name_maxsz) #define encode_open_maxsz (op_encode_hdr_maxsz + \ @@ -132,14 +142,52 @@ static int nfs4_stat_to_errno(int); encode_opentype_maxsz + \ encode_claim_null_maxsz) #define decode_ace_maxsz (3 + nfs4_owner_maxsz) -#define decode_delegation_maxsz (1 + XDR_QUADLEN(NFS4_STATEID_SIZE) + 1 + \ +#define decode_delegation_maxsz (1 + decode_stateid_maxsz + 1 + \ decode_ace_maxsz) #define decode_change_info_maxsz (5) #define decode_open_maxsz (op_decode_hdr_maxsz + \ - XDR_QUADLEN(NFS4_STATEID_SIZE) + \ + decode_stateid_maxsz + \ decode_change_info_maxsz + 1 + \ nfs4_fattr_bitmap_maxsz + \ decode_delegation_maxsz) +#define encode_open_confirm_maxsz \ + (op_encode_hdr_maxsz + \ + encode_stateid_maxsz + 1) +#define decode_open_confirm_maxsz \ + (op_decode_hdr_maxsz + \ + decode_stateid_maxsz) +#define encode_open_downgrade_maxsz \ + (op_encode_hdr_maxsz + \ + encode_stateid_maxsz + 1 + \ + encode_share_access_maxsz) +#define decode_open_downgrade_maxsz \ + (op_decode_hdr_maxsz + \ + decode_stateid_maxsz) +#define encode_close_maxsz (op_encode_hdr_maxsz + \ + 1 + encode_stateid_maxsz) +#define decode_close_maxsz (op_decode_hdr_maxsz + \ + decode_stateid_maxsz) +#define encode_setattr_maxsz (op_encode_hdr_maxsz + \ + encode_stateid_maxsz + \ + encode_attrs_maxsz) +#define decode_setattr_maxsz (op_decode_hdr_maxsz + \ + nfs4_fattr_bitmap_maxsz) +#define encode_read_maxsz (op_encode_hdr_maxsz + \ + encode_stateid_maxsz + 3) +#define decode_read_maxsz (op_decode_hdr_maxsz + 2) +#define encode_readdir_maxsz (op_encode_hdr_maxsz + \ + 2 + encode_verifier_maxsz + 5) +#define decode_readdir_maxsz (op_decode_hdr_maxsz + \ + decode_verifier_maxsz) +#define encode_readlink_maxsz (op_encode_hdr_maxsz) +#define decode_readlink_maxsz (op_decode_hdr_maxsz + 1) +#define encode_write_maxsz (op_encode_hdr_maxsz + \ + encode_stateid_maxsz + 4) +#define decode_write_maxsz (op_decode_hdr_maxsz + \ + 2 + decode_verifier_maxsz) +#define encode_commit_maxsz (op_encode_hdr_maxsz + 3) +#define decode_commit_maxsz (op_decode_hdr_maxsz + \ + decode_verifier_maxsz) #define encode_remove_maxsz (op_encode_hdr_maxsz + \ nfs4_name_maxsz) #define encode_rename_maxsz (op_encode_hdr_maxsz + \ @@ -148,19 +196,44 @@ static int nfs4_stat_to_errno(int); #define encode_link_maxsz (op_encode_hdr_maxsz + \ nfs4_name_maxsz) #define decode_link_maxsz (op_decode_hdr_maxsz + 5) +#define encode_lock_maxsz (op_encode_hdr_maxsz + \ + 7 + \ + 1 + encode_stateid_maxsz + 8) +#define decode_lock_denied_maxsz \ + (8 + decode_lockowner_maxsz) +#define decode_lock_maxsz (op_decode_hdr_maxsz + \ + decode_lock_denied_maxsz) +#define encode_lockt_maxsz (op_encode_hdr_maxsz + 12) +#define decode_lockt_maxsz (op_decode_hdr_maxsz + \ + decode_lock_denied_maxsz) +#define encode_locku_maxsz (op_encode_hdr_maxsz + 3 + \ + encode_stateid_maxsz + \ + 4) +#define decode_locku_maxsz (op_decode_hdr_maxsz + \ + decode_stateid_maxsz) +#define encode_access_maxsz (op_encode_hdr_maxsz + 1) +#define decode_access_maxsz (op_decode_hdr_maxsz + 2) #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ 1 + nfs4_name_maxsz + \ 1 + \ nfs4_fattr_maxsz) #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) #define encode_create_maxsz (op_encode_hdr_maxsz + \ - 2 + nfs4_name_maxsz + \ - nfs4_fattr_maxsz) + 1 + 2 + nfs4_name_maxsz + \ + encode_attrs_maxsz) #define decode_create_maxsz (op_decode_hdr_maxsz + \ decode_change_info_maxsz + \ nfs4_fattr_bitmap_maxsz) +#define encode_statfs_maxsz (encode_getattr_maxsz) +#define decode_statfs_maxsz (decode_getattr_maxsz) #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) +#define encode_getacl_maxsz (encode_getattr_maxsz) +#define decode_getacl_maxsz (op_decode_hdr_maxsz + \ + nfs4_fattr_bitmap_maxsz + 1) +#define encode_setacl_maxsz (op_encode_hdr_maxsz + \ + encode_stateid_maxsz + 3) +#define decode_setacl_maxsz (decode_setattr_maxsz) #define encode_fs_locations_maxsz \ (encode_getattr_maxsz) #define decode_fs_locations_maxsz \ @@ -169,37 +242,37 @@ static int nfs4_stat_to_errno(int); #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 7) + encode_read_maxsz) #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 2) + decode_read_maxsz) #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz) + encode_readlink_maxsz) #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz) + decode_readlink_maxsz) #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 9) + encode_readdir_maxsz) #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 2) + decode_readdir_maxsz) #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 8 + \ + encode_write_maxsz + \ encode_getattr_maxsz) #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4 + \ + decode_write_maxsz + \ decode_getattr_maxsz) #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 3 + \ + encode_commit_maxsz + \ encode_getattr_maxsz) #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 2 + \ + decode_commit_maxsz + \ decode_getattr_maxsz) #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ @@ -217,13 +290,14 @@ static int nfs4_stat_to_errno(int); decode_getattr_maxsz + \ decode_restorefh_maxsz + \ decode_getattr_maxsz) -#define NFS4_enc_open_confirm_sz \ - (compound_encode_hdr_maxsz + \ - encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 5) -#define NFS4_dec_open_confirm_sz (compound_decode_hdr_maxsz + \ - decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4) +#define NFS4_enc_open_confirm_sz \ + (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_open_confirm_maxsz) +#define NFS4_dec_open_confirm_sz \ + (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_open_confirm_maxsz) #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_open_maxsz + \ @@ -234,31 +308,30 @@ static int nfs4_stat_to_errno(int); decode_getattr_maxsz) #define NFS4_enc_open_downgrade_sz \ (compound_encode_hdr_maxsz + \ - encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 7 + \ - encode_getattr_maxsz) + encode_putfh_maxsz + \ + encode_open_downgrade_maxsz + \ + encode_getattr_maxsz) #define NFS4_dec_open_downgrade_sz \ (compound_decode_hdr_maxsz + \ - decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4 + \ - decode_getattr_maxsz) -#define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ - encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 5 + \ - encode_getattr_maxsz) -#define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ - decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4 + \ - decode_getattr_maxsz) -#define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ - encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 4 + \ - nfs4_fattr_maxsz + \ - encode_getattr_maxsz) -#define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ - decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 3 + \ - nfs4_fattr_maxsz) + decode_putfh_maxsz + \ + decode_open_downgrade_maxsz + \ + decode_getattr_maxsz) +#define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_close_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_close_maxsz + \ + decode_getattr_maxsz) +#define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_setattr_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_setattr_maxsz + \ + decode_getattr_maxsz) #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_fsinfo_maxsz) @@ -285,39 +358,28 @@ static int nfs4_stat_to_errno(int); decode_fsinfo_maxsz) #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_getattr_maxsz + \ - op_encode_hdr_maxsz + \ - 1 + 1 + 2 + 2 + \ - 1 + 4 + 1 + 2 + \ - lock_owner_id_maxsz) + encode_lock_maxsz) #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_getattr_maxsz + \ - op_decode_hdr_maxsz + \ - 2 + 2 + 1 + 2 + \ - lock_owner_id_maxsz) + decode_lock_maxsz) #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_getattr_maxsz + \ - op_encode_hdr_maxsz + \ - 1 + 2 + 2 + 2 + \ - lock_owner_id_maxsz) -#define NFS4_dec_lockt_sz (NFS4_dec_lock_sz) + encode_lockt_maxsz) +#define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_lockt_maxsz) #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_getattr_maxsz + \ - op_encode_hdr_maxsz + \ - 1 + 1 + 4 + 2 + 2) + encode_locku_maxsz) #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_getattr_maxsz + \ - op_decode_hdr_maxsz + 4) + decode_locku_maxsz) #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 1) + encode_access_maxsz) #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 2) + decode_access_maxsz) #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_getattr_maxsz) @@ -416,10 +478,10 @@ static int nfs4_stat_to_errno(int); decode_getattr_maxsz) #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_getattr_maxsz) + encode_statfs_maxsz) #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 12) + decode_statfs_maxsz) #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_getattr_maxsz) @@ -435,18 +497,16 @@ static int nfs4_stat_to_errno(int); decode_getattr_maxsz) #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_getattr_maxsz) + encode_getacl_maxsz) #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + \ - nfs4_fattr_bitmap_maxsz + 1) + decode_getacl_maxsz) #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 4 + \ - nfs4_fattr_bitmap_maxsz + 1) + encode_setacl_maxsz) #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) + decode_setacl_maxsz) #define NFS4_enc_fs_locations_sz \ (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ -- cgit v1.2.3-70-g09d2 From d6ac02dfaa6c423874839fe289c7320624aa9288 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 19 Jul 2007 10:03:37 -0400 Subject: NFSv4: Fix the readdir reply buffer alignment Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5eb92f1e2e1..bec171a493a 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1168,12 +1168,10 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) { - struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; uint32_t attrs[2] = { FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, FATTR4_WORD1_MOUNTED_ON_FILEID, }; - int replen; __be32 *p; RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20); @@ -1198,17 +1196,6 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg attrs[0] & readdir->bitmask[0], attrs[1] & readdir->bitmask[1]); - /* set up reply kvec - * toplevel_status + taglen + rescount + OP_PUTFH + status - * + OP_READDIR + status + verifer(2) = 9 - */ - replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; - xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, - readdir->pgbase, readdir->count); - dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", - __FUNCTION__, replen, readdir->pages, - readdir->pgbase, readdir->count); - return 0; } @@ -1815,6 +1802,8 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf struct compound_hdr hdr = { .nops = 2, }; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; + int replen; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); @@ -1823,6 +1812,18 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf if(status) goto out; status = encode_readdir(&xdr, args, req); + + /* set up reply kvec + * toplevel_status + taglen + rescount + OP_PUTFH + status + * + OP_READDIR + status + verifer(2) = 9 + */ + replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readdir_sz) << 2; + xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, + args->pgbase, args->count); + dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", + __FUNCTION__, replen, args->pages, + args->pgbase, args->count); + out: return status; } -- cgit v1.2.3-70-g09d2 From e3a535e1739a9da3cc316ccdfe5cd4bf84d745ac Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 19 Jul 2007 10:03:38 -0400 Subject: NFSv4: Fix the nfsv4 readlink reply buffer alignment Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index bec171a493a..7b73ca8be90 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1201,21 +1201,11 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req) { - struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; - unsigned int replen; __be32 *p; RESERVE_SPACE(4); WRITE32(OP_READLINK); - /* set up reply kvec - * toplevel_status + taglen + rescount + OP_PUTFH + status - * + OP_READLINK + status + string length = 8 - */ - replen = (RPC_REPHDRSIZE + auth->au_rslack + 8) << 2; - xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, - readlink->pgbase, readlink->pglen); - return 0; } @@ -1781,6 +1771,8 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n struct compound_hdr hdr = { .nops = 2, }; + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; + unsigned int replen; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); @@ -1789,6 +1781,15 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n if(status) goto out; status = encode_readlink(&xdr, args, req); + + /* set up reply kvec + * toplevel_status + taglen + rescount + OP_PUTFH + status + * + OP_READLINK + status + string length = 8 + */ + replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2; + xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, + args->pgbase, args->pglen); + out: return status; } -- cgit v1.2.3-70-g09d2 From 3062c532ad410fe0e8320566fe2879a396be6701 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 14 Jul 2007 17:36:45 -0400 Subject: NFS: Use dentry->d_time to store the parent directory verifier. This will free up the d_fsdata field for other use. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 322141f4ab4..0fa1dbcdadb 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -654,7 +654,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) if (IS_ROOT(dentry)) return 1; - verf = (unsigned long)dentry->d_fsdata; + verf = dentry->d_time; if (nfs_caches_unstable(dir) || verf != NFS_I(dir)->cache_change_attribute) return 0; @@ -663,7 +663,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) { - dentry->d_fsdata = (void *)verf; + dentry->d_time = verf; } static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf) -- cgit v1.2.3-70-g09d2 From 4fdc17b2a7f4d9db5b08e0f963d0027f714e4104 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 14 Jul 2007 15:39:57 -0400 Subject: NFS: Introduce struct nfs_removeargs+nfs_removeres We need a common structure for setting up an unlink() rpc call in order to fix the asynchronous unlink code. Signed-off-by: Trond Myklebust --- fs/nfs/nfs2xdr.c | 19 ++++++++++++++++--- fs/nfs/nfs3proc.c | 34 +++++++++++++++++----------------- fs/nfs/nfs3xdr.c | 24 ++++++++++++++++++++++-- fs/nfs/nfs4proc.c | 31 +++++++++++++++---------------- fs/nfs/nfs4xdr.c | 8 ++++---- fs/nfs/proc.c | 20 ++++++++++---------- include/linux/nfs_xdr.h | 27 +++++++++++++++------------ 7 files changed, 99 insertions(+), 64 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 7fcc78f2aa7..c5fce756720 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -43,6 +43,7 @@ #define NFS_entry_sz (NFS_filename_sz+3) #define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz) +#define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz) #define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz) #define NFS_readlinkargs_sz (NFS_fhandle_sz) #define NFS_readargs_sz (NFS_fhandle_sz+3) @@ -66,7 +67,7 @@ * Common NFS XDR functions as inlines */ static inline __be32 * -xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle) +xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fhandle) { memcpy(p, fhandle->data, NFS2_FHSIZE); return p + XDR_QUADLEN(NFS2_FHSIZE); @@ -204,7 +205,7 @@ nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args) /* * Encode directory ops argument - * LOOKUP, REMOVE, RMDIR + * LOOKUP, RMDIR */ static int nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args) @@ -215,6 +216,18 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args) return 0; } +/* + * Encode REMOVE argument + */ +static int +nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args) +{ + p = xdr_encode_fhandle(p, args->fh); + p = xdr_encode_array(p, args->name.name, args->name.len); + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + /* * Arguments to a READ call. Since we read data directly into the page * cache, we also set up the reply iovec here so that iov[1] points @@ -705,7 +718,7 @@ struct rpc_procinfo nfs_procedures[] = { PROC(READ, readargs, readres, 3), PROC(WRITE, writeargs, writeres, 4), PROC(CREATE, createargs, diropres, 0), - PROC(REMOVE, diropargs, stat, 0), + PROC(REMOVE, removeargs, stat, 0), PROC(RENAME, renameargs, stat, 0), PROC(LINK, linkargs, stat, 0), PROC(SYMLINK, symlinkargs, stat, 0), diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 814d886b6aa..eac07f2c99d 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -349,23 +349,23 @@ out: static int nfs3_proc_remove(struct inode *dir, struct qstr *name) { - struct nfs_fattr dir_attr; - struct nfs3_diropargs arg = { - .fh = NFS_FH(dir), - .name = name->name, - .len = name->len + struct nfs_removeargs arg = { + .fh = NFS_FH(dir), + .name.len = name->len, + .name.name = name->name, }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE], - .rpc_argp = &arg, - .rpc_resp = &dir_attr, + struct nfs_removeres res; + struct rpc_message msg = { + .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE], + .rpc_argp = &arg, + .rpc_resp = &res, }; int status; dprintk("NFS call remove %s\n", name->name); - nfs_fattr_init(&dir_attr); + nfs_fattr_init(&res.dir_attr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); - nfs_post_op_update_inode(dir, &dir_attr); + nfs_post_op_update_inode(dir, &res.dir_attr); dprintk("NFS reply remove: %d\n", status); return status; } @@ -374,17 +374,17 @@ static int nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) { struct unlinkxdr { - struct nfs3_diropargs arg; - struct nfs_fattr res; + struct nfs_removeargs arg; + struct nfs_removeres res; } *ptr; ptr = kmalloc(sizeof(*ptr), GFP_KERNEL); if (!ptr) return -ENOMEM; ptr->arg.fh = NFS_FH(dir->d_inode); - ptr->arg.name = name->name; - ptr->arg.len = name->len; - nfs_fattr_init(&ptr->res); + ptr->arg.name.name = name->name; + ptr->arg.name.len = name->len; + nfs_fattr_init(&ptr->res.dir_attr); msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; msg->rpc_argp = &ptr->arg; msg->rpc_resp = &ptr->res; @@ -400,7 +400,7 @@ nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task) if (nfs3_async_handle_jukebox(task, dir->d_inode)) return 1; if (msg->rpc_argp) { - dir_attr = (struct nfs_fattr*)msg->rpc_resp; + dir_attr = &((struct nfs_removeres*)msg->rpc_resp)->dir_attr; nfs_post_op_update_inode(dir->d_inode, dir_attr); kfree(msg->rpc_argp); } diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index b4647a22f34..d9e08f0cf2a 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -50,6 +50,7 @@ #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3) #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz) +#define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz) #define NFS3_accessargs_sz (NFS3_fh_sz+1) #define NFS3_readlinkargs_sz (NFS3_fh_sz) #define NFS3_readargs_sz (NFS3_fh_sz+3) @@ -65,6 +66,7 @@ #define NFS3_attrstat_sz (1+NFS3_fattr_sz) #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz) +#define NFS3_removeres_sz (NFS3_wccstat_sz) #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1) @@ -106,7 +108,7 @@ static struct { * Common NFS XDR functions as inlines */ static inline __be32 * -xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh) +xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh) { return xdr_encode_array(p, fh->data, fh->size); } @@ -299,6 +301,18 @@ nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args) return 0; } +/* + * Encode REMOVE argument + */ +static int +nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args) +{ + p = xdr_encode_fhandle(p, args->fh); + p = xdr_encode_array(p, args->name.name, args->name.len); + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + /* * Encode access() argument */ @@ -736,6 +750,12 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) return status; } +static int +nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res) +{ + return nfs3_xdr_wccstat(req, p, &res->dir_attr); +} + /* * Decode LOOKUP reply */ @@ -1126,7 +1146,7 @@ struct rpc_procinfo nfs3_procedures[] = { PROC(MKDIR, mkdirargs, createres, 0), PROC(SYMLINK, symlinkargs, createres, 0), PROC(MKNOD, mknodargs, createres, 0), - PROC(REMOVE, diropargs, wccstat, 0), + PROC(REMOVE, removeargs, removeres, 0), PROC(RMDIR, diropargs, wccstat, 0), PROC(RENAME, renameargs, renameres, 0), PROC(LINK, linkargs, linkres, 0), diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7ead63e065a..23dc25dbc6f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1925,28 +1925,27 @@ out: static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) { struct nfs_server *server = NFS_SERVER(dir); - struct nfs4_remove_arg args = { + struct nfs_removeargs args = { .fh = NFS_FH(dir), - .name = name, + .name.len = name->len, + .name.name = name->name, .bitmask = server->attr_bitmask, }; - struct nfs_fattr dir_attr; - struct nfs4_remove_res res = { + struct nfs_removeres res = { .server = server, - .dir_attr = &dir_attr, }; struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], - .rpc_argp = &args, - .rpc_resp = &res, + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], + .rpc_argp = &args, + .rpc_resp = &res, }; int status; - nfs_fattr_init(res.dir_attr); + nfs_fattr_init(&res.dir_attr); status = rpc_call_sync(server->client, &msg, 0); if (status == 0) { update_changeattr(dir, &res.cinfo); - nfs_post_op_update_inode(dir, res.dir_attr); + nfs_post_op_update_inode(dir, &res.dir_attr); } return status; } @@ -1964,9 +1963,8 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name) } struct unlink_desc { - struct nfs4_remove_arg args; - struct nfs4_remove_res res; - struct nfs_fattr dir_attr; + struct nfs_removeargs args; + struct nfs_removeres res; }; static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, @@ -1980,10 +1978,11 @@ static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, return -ENOMEM; up->args.fh = NFS_FH(dir->d_inode); - up->args.name = name; + up->args.name.len = name->len; + up->args.name.name = name->name; up->args.bitmask = server->attr_bitmask; up->res.server = server; - up->res.dir_attr = &up->dir_attr; + nfs_fattr_init(&up->res.dir_attr); msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; msg->rpc_argp = &up->args; @@ -1999,7 +1998,7 @@ static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) if (msg->rpc_resp != NULL) { up = container_of(msg->rpc_resp, struct unlink_desc, res); update_changeattr(dir->d_inode, &up->res.cinfo); - nfs_post_op_update_inode(dir->d_inode, up->res.dir_attr); + nfs_post_op_update_inode(dir->d_inode, &up->res.dir_attr); kfree(up); msg->rpc_resp = NULL; msg->rpc_argp = NULL; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 7b73ca8be90..badd73b7ca1 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1435,7 +1435,7 @@ out: /* * Encode REMOVE request */ -static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args) +static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1447,7 +1447,7 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs encode_compound_hdr(&xdr, &hdr); if ((status = encode_putfh(&xdr, args->fh)) != 0) goto out; - if ((status = encode_remove(&xdr, args->name)) != 0) + if ((status = encode_remove(&xdr, &args->name)) != 0) goto out; status = encode_getfattr(&xdr, args->bitmask); out: @@ -3835,7 +3835,7 @@ out: /* * Decode REMOVE response */ -static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res) +static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3848,7 +3848,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re goto out; if ((status = decode_remove(&xdr, &res->cinfo)) != 0) goto out; - decode_getfattr(&xdr, res->dir_attr, res->server); + decode_getfattr(&xdr, &res->dir_attr, res->server); out: return status; } diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 7be0ee2782c..3b3eb692e0f 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -272,14 +272,14 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, static int nfs_proc_remove(struct inode *dir, struct qstr *name) { - struct nfs_diropargs arg = { - .fh = NFS_FH(dir), - .name = name->name, - .len = name->len + struct nfs_removeargs arg = { + .fh = NFS_FH(dir), + .name.len = name->len, + .name.name = name->name, }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_REMOVE], - .rpc_argp = &arg, + struct rpc_message msg = { + .rpc_proc = &nfs_procedures[NFSPROC_REMOVE], + .rpc_argp = &arg, }; int status; @@ -294,14 +294,14 @@ nfs_proc_remove(struct inode *dir, struct qstr *name) static int nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) { - struct nfs_diropargs *arg; + struct nfs_removeargs *arg; arg = kmalloc(sizeof(*arg), GFP_KERNEL); if (!arg) return -ENOMEM; arg->fh = NFS_FH(dir->d_inode); - arg->name = name->name; - arg->len = name->len; + arg->name.name = name->name; + arg->name.len = name->len; msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE]; msg->rpc_argp = arg; return 0; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 38d77681cf2..7babcb16300 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -277,6 +277,21 @@ struct nfs_writeres { const struct nfs_server *server; }; +/* + * Common arguments to the unlink call + */ +struct nfs_removeargs { + const struct nfs_fh *fh; + struct qstr name; + const u32 * bitmask; +}; + +struct nfs_removeres { + const struct nfs_server *server; + struct nfs4_change_info cinfo; + struct nfs_fattr dir_attr; +}; + /* * Argument struct for decode_entry function */ @@ -631,18 +646,6 @@ struct nfs4_readlink { struct page ** pages; /* zero-copy data */ }; -struct nfs4_remove_arg { - const struct nfs_fh * fh; - const struct qstr * name; - const u32 * bitmask; -}; - -struct nfs4_remove_res { - const struct nfs_server * server; - struct nfs4_change_info cinfo; - struct nfs_fattr * dir_attr; -}; - struct nfs4_rename_arg { const struct nfs_fh * old_dir; const struct nfs_fh * new_dir; -- cgit v1.2.3-70-g09d2 From e4eff1a622edd6ab7b73acd5d8763aa2fa3fee49 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 14 Jul 2007 15:39:58 -0400 Subject: SUNRPC: Clean up the sillyrename code Fix a couple of bugs: - Don't rely on the parent dentry still being valid when the call completes. Fixes a race with shrink_dcache_for_umount_subtree() - Don't remove the file if the filehandle has been labelled as stale. Fix a couple of inefficiencies - Remove the global list of sillyrenamed files. Instead we can cache the sillyrename information in the dentry->d_fsdata - Move common code from unlink_setup/unlink_done into fs/nfs/unlink.c Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 4 +- fs/nfs/nfs3proc.c | 38 +++------- fs/nfs/nfs4proc.c | 50 ++++--------- fs/nfs/proc.c | 26 ++----- fs/nfs/unlink.c | 195 +++++++++++++++++++++--------------------------- include/linux/nfs_fs.h | 4 +- include/linux/nfs_xdr.h | 5 +- 7 files changed, 120 insertions(+), 202 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 0fa1dbcdadb..ea97408e423 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -869,7 +869,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { lock_kernel(); drop_nlink(inode); - nfs_complete_unlink(dentry); + nfs_complete_unlink(dentry, inode); unlock_kernel(); } /* When creating a negative dentry, we want to renew d_time */ @@ -1411,7 +1411,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) nfs_renew_times(dentry); nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); d_move(dentry, sdentry); - error = nfs_async_unlink(dentry); + error = nfs_async_unlink(dir, dentry); /* If we return 0 we don't unlink */ } dput(sdentry); diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index eac07f2c99d..c7ca5d70870 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -370,41 +370,21 @@ nfs3_proc_remove(struct inode *dir, struct qstr *name) return status; } -static int -nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) +static void +nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) { - struct unlinkxdr { - struct nfs_removeargs arg; - struct nfs_removeres res; - } *ptr; - - ptr = kmalloc(sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - ptr->arg.fh = NFS_FH(dir->d_inode); - ptr->arg.name.name = name->name; - ptr->arg.name.len = name->len; - nfs_fattr_init(&ptr->res.dir_attr); msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; - msg->rpc_argp = &ptr->arg; - msg->rpc_resp = &ptr->res; - return 0; } static int -nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task) +nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir) { - struct rpc_message *msg = &task->tk_msg; - struct nfs_fattr *dir_attr; - - if (nfs3_async_handle_jukebox(task, dir->d_inode)) - return 1; - if (msg->rpc_argp) { - dir_attr = &((struct nfs_removeres*)msg->rpc_resp)->dir_attr; - nfs_post_op_update_inode(dir->d_inode, dir_attr); - kfree(msg->rpc_argp); - } - return 0; + struct nfs_removeres *res; + if (nfs3_async_handle_jukebox(task, dir)) + return 0; + res = task->tk_msg.rpc_resp; + nfs_post_op_update_inode(dir, &res->dir_attr); + return 1; } static int diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 23dc25dbc6f..6ca2795ccd9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1962,48 +1962,26 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name) return err; } -struct unlink_desc { - struct nfs_removeargs args; - struct nfs_removeres res; -}; - -static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, - struct qstr *name) +static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) { - struct nfs_server *server = NFS_SERVER(dir->d_inode); - struct unlink_desc *up; + struct nfs_server *server = NFS_SERVER(dir); + struct nfs_removeargs *args = msg->rpc_argp; + struct nfs_removeres *res = msg->rpc_resp; - up = kmalloc(sizeof(*up), GFP_KERNEL); - if (!up) - return -ENOMEM; - - up->args.fh = NFS_FH(dir->d_inode); - up->args.name.len = name->len; - up->args.name.name = name->name; - up->args.bitmask = server->attr_bitmask; - up->res.server = server; - nfs_fattr_init(&up->res.dir_attr); - + args->bitmask = server->attr_bitmask; + res->server = server; msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; - msg->rpc_argp = &up->args; - msg->rpc_resp = &up->res; - return 0; } -static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) +static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) { - struct rpc_message *msg = &task->tk_msg; - struct unlink_desc *up; - - if (msg->rpc_resp != NULL) { - up = container_of(msg->rpc_resp, struct unlink_desc, res); - update_changeattr(dir->d_inode, &up->res.cinfo); - nfs_post_op_update_inode(dir->d_inode, &up->res.dir_attr); - kfree(up); - msg->rpc_resp = NULL; - msg->rpc_argp = NULL; - } - return 0; + struct nfs_removeres *res = task->tk_msg.rpc_resp; + + if (nfs4_async_handle_error(task, res->server) == -EAGAIN) + return 0; + update_changeattr(dir, &res->cinfo); + nfs_post_op_update_inode(dir, &res->dir_attr); + return 1; } static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 3b3eb692e0f..845cdde1d8b 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -291,32 +291,16 @@ nfs_proc_remove(struct inode *dir, struct qstr *name) return status; } -static int -nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) +static void +nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) { - struct nfs_removeargs *arg; - - arg = kmalloc(sizeof(*arg), GFP_KERNEL); - if (!arg) - return -ENOMEM; - arg->fh = NFS_FH(dir->d_inode); - arg->name.name = name->name; - arg->name.len = name->len; msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE]; - msg->rpc_argp = arg; - return 0; } -static int -nfs_proc_unlink_done(struct dentry *dir, struct rpc_task *task) +static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) { - struct rpc_message *msg = &task->tk_msg; - - if (msg->rpc_argp) { - nfs_mark_for_revalidate(dir->d_inode); - kfree(msg->rpc_argp); - } - return 0; + nfs_mark_for_revalidate(dir); + return 1; } static int diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 0e28189c215..045ab805c17 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -3,7 +3,6 @@ * * nfs sillydelete handling * - * NOTE: we rely on holding the BKL for list manipulation protection. */ #include @@ -15,46 +14,23 @@ struct nfs_unlinkdata { - struct nfs_unlinkdata *next; - struct dentry *dir, *dentry; - struct qstr name; - struct rpc_task task; + struct nfs_removeargs args; + struct nfs_removeres res; + struct inode *dir; struct rpc_cred *cred; - unsigned int count; }; -static struct nfs_unlinkdata *nfs_deletes; -static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue"); - -/** - * nfs_detach_unlinkdata - Remove asynchronous unlink from global list - * @data: pointer to descriptor - */ -static inline void -nfs_detach_unlinkdata(struct nfs_unlinkdata *data) -{ - struct nfs_unlinkdata **q; - - for (q = &nfs_deletes; *q != NULL; q = &((*q)->next)) { - if (*q == data) { - *q = data->next; - break; - } - } -} - /** - * nfs_put_unlinkdata - release data from a sillydelete operation. + * nfs_free_unlinkdata - release data from a sillydelete operation. * @data: pointer to unlink structure. */ static void -nfs_put_unlinkdata(struct nfs_unlinkdata *data) +nfs_free_unlinkdata(struct nfs_unlinkdata *data) { - if (--data->count == 0) { - nfs_detach_unlinkdata(data); - kfree(data->name.name); - kfree(data); - } + iput(data->dir); + put_rpccred(data->cred); + kfree(data->args.name.name); + kfree(data); } #define NAME_ALLOC_LEN(len) ((len+16) & ~15) @@ -63,50 +39,36 @@ nfs_put_unlinkdata(struct nfs_unlinkdata *data) * @dentry: pointer to dentry * @data: nfs_unlinkdata */ -static inline void -nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data) +static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data) { char *str; int len = dentry->d_name.len; - str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL); + str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL); if (!str) - return; - memcpy(str, dentry->d_name.name, len); - if (!data->name.len) { - data->name.len = len; - data->name.name = str; - } else - kfree(str); + return -ENOMEM; + data->args.name.len = len; + data->args.name.name = str; + return 0; } /** * nfs_async_unlink_init - Initialize the RPC info - * @task: rpc_task of the sillydelete - * - * We delay initializing RPC info until after the call to dentry_iput() - * in order to minimize races against rename(). + * task: rpc_task of the sillydelete */ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) { - struct nfs_unlinkdata *data = calldata; - struct dentry *dir = data->dir; - struct rpc_message msg = { - .rpc_cred = data->cred, + struct nfs_unlinkdata *data = calldata; + struct inode *dir = data->dir; + struct rpc_message msg = { + .rpc_argp = &data->args, + .rpc_resp = &data->res, + .rpc_cred = data->cred, }; - int status = -ENOENT; - - if (!data->name.len) - goto out_err; - status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name); - if (status < 0) - goto out_err; - nfs_begin_data_update(dir->d_inode); + nfs_begin_data_update(dir); + NFS_PROTO(dir)->unlink_setup(&msg, dir); rpc_call_setup(task, &msg, 0); - return; - out_err: - rpc_exit(task, status); } /** @@ -117,19 +79,13 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) */ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) { - struct nfs_unlinkdata *data = calldata; - struct dentry *dir = data->dir; - struct inode *dir_i; - - if (!dir) - return; - dir_i = dir->d_inode; - nfs_end_data_update(dir_i); - if (NFS_PROTO(dir_i)->unlink_done(dir, task)) - return; - put_rpccred(data->cred); - data->cred = NULL; - dput(dir); + struct nfs_unlinkdata *data = calldata; + struct inode *dir = data->dir; + + if (!NFS_PROTO(dir)->unlink_done(task, dir)) + rpc_restart_call(task); + else + nfs_end_data_update(dir); } /** @@ -142,7 +98,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) static void nfs_async_unlink_release(void *calldata) { struct nfs_unlinkdata *data = calldata; - nfs_put_unlinkdata(data); + nfs_free_unlinkdata(data); } static const struct rpc_call_ops nfs_unlink_ops = { @@ -151,73 +107,94 @@ static const struct rpc_call_ops nfs_unlink_ops = { .rpc_release = nfs_async_unlink_release, }; +static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data) +{ + struct rpc_task *task; + struct dentry *parent; + struct inode *dir; + + if (nfs_copy_dname(dentry, data) < 0) + goto out_free; + + parent = dget_parent(dentry); + if (parent == NULL) + goto out_free; + dir = igrab(parent->d_inode); + dput(parent); + if (dir == NULL) + goto out_free; + + data->dir = dir; + data->args.fh = NFS_FH(dir); + nfs_fattr_init(&data->res.dir_attr); + + task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data); + if (!IS_ERR(task)) + rpc_put_task(task); + return 1; +out_free: + return 0; +} + /** * nfs_async_unlink - asynchronous unlinking of a file + * @dir: parent directory of dentry * @dentry: dentry to unlink */ int -nfs_async_unlink(struct dentry *dentry) +nfs_async_unlink(struct inode *dir, struct dentry *dentry) { - struct dentry *dir = dentry->d_parent; - struct nfs_unlinkdata *data; - struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); - int status = -ENOMEM; + struct nfs_unlinkdata *data; + int status = -ENOMEM; data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) + if (data == NULL) goto out; - data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); + data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); if (IS_ERR(data->cred)) { status = PTR_ERR(data->cred); goto out_free; } - data->dir = dget(dir); - data->dentry = dentry; - - data->next = nfs_deletes; - nfs_deletes = data; - data->count = 1; - - rpc_init_task(&data->task, clnt, RPC_TASK_ASYNC, &nfs_unlink_ops, data); + status = -EBUSY; spin_lock(&dentry->d_lock); + if (dentry->d_flags & DCACHE_NFSFS_RENAMED) + goto out_unlock; dentry->d_flags |= DCACHE_NFSFS_RENAMED; + dentry->d_fsdata = data; spin_unlock(&dentry->d_lock); - - rpc_sleep_on(&nfs_delete_queue, &data->task, NULL, NULL); - status = 0; - out: - return status; + return 0; +out_unlock: + spin_unlock(&dentry->d_lock); + put_rpccred(data->cred); out_free: kfree(data); +out: return status; } /** * nfs_complete_unlink - Initialize completion of the sillydelete * @dentry: dentry to delete + * @inode: inode * * Since we're most likely to be called by dentry_iput(), we * only use the dentry to find the sillydelete. We then copy the name * into the qstr. */ void -nfs_complete_unlink(struct dentry *dentry) +nfs_complete_unlink(struct dentry *dentry, struct inode *inode) { - struct nfs_unlinkdata *data; + struct nfs_unlinkdata *data = NULL; - for(data = nfs_deletes; data != NULL; data = data->next) { - if (dentry == data->dentry) - break; - } - if (!data) - return; - data->count++; - nfs_copy_dname(dentry, data); spin_lock(&dentry->d_lock); - dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; + if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { + dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; + data = dentry->d_fsdata; + } spin_unlock(&dentry->d_lock); - rpc_wake_up_task(&data->task); - nfs_put_unlinkdata(data); + + if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data))) + nfs_free_unlinkdata(data); } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index c098ae194f7..9ba4aec37c5 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -407,8 +407,8 @@ extern void nfs_release_automount_timer(void); /* * linux/fs/nfs/unlink.c */ -extern int nfs_async_unlink(struct dentry *); -extern void nfs_complete_unlink(struct dentry *); +extern int nfs_async_unlink(struct inode *dir, struct dentry *dentry); +extern void nfs_complete_unlink(struct dentry *dentry, struct inode *); /* * linux/fs/nfs/write.c diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 7babcb16300..cf74a4db84a 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -791,9 +791,8 @@ struct nfs_rpc_ops { int (*create) (struct inode *, struct dentry *, struct iattr *, int, struct nameidata *); int (*remove) (struct inode *, struct qstr *); - int (*unlink_setup) (struct rpc_message *, - struct dentry *, struct qstr *); - int (*unlink_done) (struct dentry *, struct rpc_task *); + void (*unlink_setup) (struct rpc_message *, struct inode *dir); + int (*unlink_done) (struct rpc_task *, struct inode *); int (*rename) (struct inode *, struct qstr *, struct inode *, struct qstr *); int (*link) (struct inode *, struct inode *, struct qstr *); -- cgit v1.2.3-70-g09d2 From f9d888fcd9665b863fa042212a3ee7b4c51399f6 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Sun, 15 Jul 2007 20:14:32 +0300 Subject: NFSv4: debug print ntohl(status) in nfs client callback xdr code status in nfs client callback xdr code is passed in network order. print it in host order for better readability. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- fs/nfs/callback_xdr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'fs/nfs') diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 849a2029975..058ade7efe7 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -179,7 +179,7 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr args->addr = svc_addr_in(rqstp); status = decode_bitmap(xdr, args->bitmap); out: - dprintk("%s: exit with status = %d\n", __FUNCTION__, status); + dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); return status; } @@ -200,7 +200,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, args->truncate = ntohl(*p); status = decode_fh(xdr, &args->fh); out: - dprintk("%s: exit with status = %d\n", __FUNCTION__, status); + dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); return status; } @@ -349,7 +349,7 @@ static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, status = encode_attr_mtime(xdr, res->bitmap, &res->mtime); *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1))); out: - dprintk("%s: exit with status = %d\n", __FUNCTION__, status); + dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status)); return status; } @@ -392,7 +392,7 @@ static __be32 process_op(struct svc_rqst *rqstp, status = res; if (op->encode_res != NULL && status == 0) status = op->encode_res(rqstp, xdr_out, resp); - dprintk("%s: done, status = %d\n", __FUNCTION__, status); + dprintk("%s: done, status = %d\n", __FUNCTION__, ntohl(status)); return status; } @@ -431,7 +431,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r } *hdr_res.status = status; *hdr_res.nops = htonl(nops); - dprintk("%s: done, status = %u\n", __FUNCTION__, status); + dprintk("%s: done, status = %u\n", __FUNCTION__, ntohl(status)); return rpc_success; } -- cgit v1.2.3-70-g09d2 From 0a87cf128f3d3bc6aa7b1040e73109c974ed875a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 18 Jul 2007 11:28:43 -0400 Subject: NFSv4: handle lack of clientaddr in option string If a NFSv4 mount is attempted with string based options, and the option string doesn't contain a clientaddr= option, the kernel will currently oops. Check for this situation and return a proper error. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index adffe1615c5..b34b7a711d5 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1685,6 +1685,9 @@ static int nfs4_validate_mount_data(struct nfs4_mount_data **options, dprintk("MNTPATH: %s\n", *mntpath); + if (args.client_address == NULL) + goto out_no_client_address; + *ip_addr = args.client_address; break; @@ -1705,6 +1708,10 @@ out_inval_auth: out_no_address: dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); return -EINVAL; + +out_no_client_address: + dfprintk(MOUNT, "NFS4: mount program didn't pass callback address\n"); + return -EINVAL; } /* -- cgit v1.2.3-70-g09d2 From 20c2df83d25c6a95affe6157a4c9cac4cf5ffaac Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 20 Jul 2007 10:11:58 +0900 Subject: mm: Remove slab destructors from kmem_cache_create(). Slab destructors were no longer supported after Christoph's c59def9f222d44bb7e2f0a559f2906191a0862d7 change. They've been BUGs for both slab and slub, and slob never supported them either. This rips out support for the dtor pointer from kmem_cache_create() completely and fixes up every single callsite in the kernel (there were about 224, not including the slab allocator definitions themselves, or the documentation references). Signed-off-by: Paul Mundt --- arch/arm/plat-s3c24xx/dma.c | 2 +- arch/arm26/mm/memc.c | 4 ++-- arch/i386/mm/init.c | 3 +-- arch/ia64/ia32/ia32_support.c | 2 +- arch/powerpc/kernel/rtas_flash.c | 2 +- arch/powerpc/mm/hugetlbpage.c | 2 +- arch/powerpc/mm/init_64.c | 3 +-- arch/powerpc/platforms/cell/spufs/inode.c | 2 +- arch/sh/kernel/cpu/sh4/sq.c | 3 +-- arch/sh/mm/pmb.c | 2 +- arch/sparc64/mm/tsb.c | 3 +-- block/bsg.c | 2 +- block/ll_rw_blk.c | 6 +++--- drivers/acpi/osl.c | 2 +- drivers/block/aoe/aoeblk.c | 4 ++-- drivers/ieee1394/eth1394.c | 2 +- drivers/infiniband/core/mad.c | 1 - drivers/infiniband/hw/amso1100/c2_vq.c | 2 +- drivers/infiniband/hw/ehca/ehca_av.c | 2 +- drivers/infiniband/hw/ehca/ehca_cq.c | 2 +- drivers/infiniband/hw/ehca/ehca_main.c | 2 +- drivers/infiniband/hw/ehca/ehca_mrmw.c | 4 ++-- drivers/infiniband/hw/ehca/ehca_pd.c | 2 +- drivers/infiniband/hw/ehca/ehca_qp.c | 2 +- drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +- drivers/kvm/mmu.c | 8 ++++---- drivers/md/raid5.c | 4 ++-- drivers/message/i2o/i2o_block.c | 3 +-- drivers/mtd/ubi/eba.c | 2 +- drivers/mtd/ubi/wl.c | 2 +- drivers/s390/block/dasd_devmap.c | 2 +- drivers/s390/scsi/zfcp_aux.c | 6 +++--- drivers/scsi/aic94xx/aic94xx_init.c | 4 ++-- drivers/scsi/libsas/sas_init.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 2 +- drivers/scsi/qla4xxx/ql4_os.c | 2 +- drivers/scsi/scsi.c | 2 +- drivers/scsi/scsi_lib.c | 4 ++-- drivers/scsi/scsi_tgt_lib.c | 2 +- drivers/usb/host/uhci-hcd.c | 2 +- drivers/usb/mon/mon_text.c | 2 +- fs/adfs/super.c | 4 ++-- fs/affs/super.c | 2 +- fs/afs/super.c | 3 +-- fs/befs/linuxvfs.c | 4 ++-- fs/bfs/inode.c | 4 ++-- fs/bio.c | 2 +- fs/block_dev.c | 2 +- fs/cifs/cifsfs.c | 10 +++++----- fs/coda/inode.c | 4 ++-- fs/configfs/mount.c | 2 +- fs/dcache.c | 4 ++-- fs/dcookies.c | 2 +- fs/dlm/lowcomms.c | 2 +- fs/dlm/memory.c | 2 +- fs/dnotify.c | 2 +- fs/dquot.c | 4 ++-- fs/ecryptfs/main.c | 2 +- fs/efs/super.c | 4 ++-- fs/eventpoll.c | 4 ++-- fs/ext2/super.c | 4 ++-- fs/ext3/super.c | 2 +- fs/ext4/super.c | 2 +- fs/fat/cache.c | 2 +- fs/fat/inode.c | 2 +- fs/fcntl.c | 2 +- fs/freevxfs/vxfs_super.c | 4 ++-- fs/fuse/dev.c | 2 +- fs/fuse/inode.c | 2 +- fs/gfs2/main.c | 6 +++--- fs/hfs/super.c | 2 +- fs/hfsplus/super.c | 2 +- fs/hpfs/super.c | 4 ++-- fs/hugetlbfs/inode.c | 2 +- fs/inode.c | 3 +-- fs/inotify_user.c | 4 ++-- fs/isofs/inode.c | 2 +- fs/jbd/journal.c | 8 +++----- fs/jbd/revoke.c | 4 ++-- fs/jbd2/journal.c | 8 +++----- fs/jbd2/revoke.c | 4 ++-- fs/jffs2/malloc.c | 18 +++++++++--------- fs/jffs2/super.c | 2 +- fs/jfs/jfs_metapage.c | 2 +- fs/jfs/super.c | 2 +- fs/locks.c | 2 +- fs/mbcache.c | 2 +- fs/minix/inode.c | 4 ++-- fs/namespace.c | 2 +- fs/ncpfs/inode.c | 4 ++-- fs/nfs/direct.c | 2 +- fs/nfs/inode.c | 4 ++-- fs/nfs/pagelist.c | 2 +- fs/nfs/read.c | 2 +- fs/nfs/write.c | 2 +- fs/nfsd/nfs4state.c | 8 ++++---- fs/ntfs/super.c | 10 +++++----- fs/ocfs2/dlm/dlmfs.c | 2 +- fs/ocfs2/dlm/dlmmaster.c | 2 +- fs/ocfs2/super.c | 2 +- fs/ocfs2/uptodate.c | 2 +- fs/openpromfs/inode.c | 2 +- fs/proc/inode.c | 4 ++-- fs/qnx4/inode.c | 2 +- fs/reiserfs/super.c | 2 +- fs/romfs/inode.c | 4 ++-- fs/smbfs/inode.c | 4 ++-- fs/smbfs/request.c | 2 +- fs/sysfs/mount.c | 2 +- fs/sysv/inode.c | 2 +- fs/udf/super.c | 2 +- fs/ufs/super.c | 4 ++-- fs/xfs/linux-2.6/kmem.h | 4 ++-- include/linux/i2o.h | 3 +-- include/linux/slab.h | 3 +-- ipc/mqueue.c | 2 +- kernel/fork.c | 18 +++++++++--------- kernel/nsproxy.c | 2 +- kernel/posix-timers.c | 2 +- kernel/user.c | 2 +- lib/idr.c | 2 +- lib/radix-tree.c | 2 +- mm/mempolicy.c | 4 ++-- mm/rmap.c | 2 +- mm/shmem.c | 2 +- mm/slab.c | 17 +++++++---------- mm/slob.c | 3 +-- mm/slub.c | 4 +--- net/bridge/br_fdb.c | 2 +- net/core/flow.c | 2 +- net/core/neighbour.c | 2 +- net/core/skbuff.c | 4 ++-- net/core/sock.c | 6 +++--- net/dccp/ackvec.c | 4 ++-- net/dccp/ccid.c | 2 +- net/dccp/ccids/lib/loss_interval.c | 2 +- net/dccp/ccids/lib/packet_history.c | 4 ++-- net/dccp/proto.c | 2 +- net/decnet/dn_route.c | 2 +- net/decnet/dn_table.c | 2 +- net/ipv4/fib_hash.c | 4 ++-- net/ipv4/fib_trie.c | 2 +- net/ipv4/inetpeer.c | 2 +- net/ipv4/ipmr.c | 2 +- net/ipv4/ipvs/ip_vs_conn.c | 2 +- net/ipv4/route.c | 2 +- net/ipv4/tcp.c | 2 +- net/ipv6/ip6_fib.c | 2 +- net/ipv6/route.c | 2 +- net/ipv6/xfrm6_tunnel.c | 2 +- net/netfilter/nf_conntrack_core.c | 2 +- net/netfilter/nf_conntrack_expect.c | 2 +- net/netfilter/xt_hashlimit.c | 2 +- net/rxrpc/af_rxrpc.c | 2 +- net/sctp/protocol.c | 4 ++-- net/socket.c | 3 +-- net/sunrpc/rpc_pipe.c | 2 +- net/sunrpc/sched.c | 4 ++-- net/tipc/handler.c | 2 +- net/xfrm/xfrm_input.c | 2 +- net/xfrm/xfrm_policy.c | 2 +- security/keys/key.c | 2 +- security/selinux/avc.c | 2 +- security/selinux/hooks.c | 2 +- security/selinux/ss/avtab.c | 2 +- 165 files changed, 247 insertions(+), 268 deletions(-) (limited to 'fs/nfs') diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 08d80f2f51f..6d048490c55 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -1333,7 +1333,7 @@ int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq, dma_kmem = kmem_cache_create("dma_desc", sizeof(struct s3c2410_dma_buf), 0, SLAB_HWCACHE_ALIGN, - s3c2410_dma_cache_ctor, NULL); + s3c2410_dma_cache_ctor); if (dma_kmem == NULL) { printk(KERN_ERR "dma failed to make kmem cache\n"); diff --git a/arch/arm26/mm/memc.c b/arch/arm26/mm/memc.c index 42505541a9b..ffecd857824 100644 --- a/arch/arm26/mm/memc.c +++ b/arch/arm26/mm/memc.c @@ -176,9 +176,9 @@ void __init pgtable_cache_init(void) { pte_cache = kmem_cache_create("pte-cache", sizeof(pte_t) * PTRS_PER_PTE, - 0, SLAB_PANIC, pte_cache_ctor, NULL); + 0, SLAB_PANIC, pte_cache_ctor); pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE + sizeof(pgd_t) * PTRS_PER_PGD, - 0, SLAB_PANIC, pgd_cache_ctor, NULL); + 0, SLAB_PANIC, pgd_cache_ctor); } diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 6a68b1ae061..6e72f22e6bb 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -752,8 +752,7 @@ void __init pgtable_cache_init(void) PTRS_PER_PMD*sizeof(pmd_t), PTRS_PER_PMD*sizeof(pmd_t), SLAB_PANIC, - pmd_ctor, - NULL); + pmd_ctor); if (!SHARED_KERNEL_PMD) { /* If we're in PAE mode and have a non-shared kernel pmd, then the pgd size must be a diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c index beea7a0b9dc..e13a1a1db4b 100644 --- a/arch/ia64/ia32/ia32_support.c +++ b/arch/ia64/ia32/ia32_support.c @@ -253,7 +253,7 @@ ia32_init (void) partial_page_cachep = kmem_cache_create("partial_page_cache", sizeof(struct partial_page), - 0, SLAB_PANIC, NULL, NULL); + 0, SLAB_PANIC, NULL); } #endif return 0; diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index f72118c0844..62b7bf2f3ea 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -804,7 +804,7 @@ int __init rtas_flash_init(void) flash_block_cache = kmem_cache_create("rtas_flash_cache", RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0, - rtas_block_ctor, NULL); + rtas_block_ctor); if (!flash_block_cache) { printk(KERN_ERR "%s: failed to create block cache\n", __FUNCTION__); diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 92a1b16fb7e..4835f73af30 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -542,7 +542,7 @@ static int __init hugetlbpage_init(void) HUGEPTE_TABLE_SIZE, HUGEPTE_TABLE_SIZE, 0, - zero_ctor, NULL); + zero_ctor); if (! huge_pgtable_cache) panic("hugetlbpage_init(): could not create hugepte cache\n"); diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index 1d6edf724c8..9f27bb56a61 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -178,7 +178,6 @@ void pgtable_cache_init(void) pgtable_cache[i] = kmem_cache_create(name, size, size, SLAB_PANIC, - zero_ctor, - NULL); + zero_ctor); } } diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index f37460e5bfd..7eb4d6cbcb7 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -654,7 +654,7 @@ static int __init spufs_init(void) ret = -ENOMEM; spufs_inode_cache = kmem_cache_create("spufs_inode_cache", sizeof(struct spufs_inode_info), 0, - SLAB_HWCACHE_ALIGN, spufs_init_once, NULL); + SLAB_HWCACHE_ALIGN, spufs_init_once); if (!spufs_inode_cache) goto out; diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index d7fff752e56..b98d6c3e6f3 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -371,8 +371,7 @@ static int __init sq_api_init(void) printk(KERN_NOTICE "sq: Registering store queue API.\n"); sq_cache = kmem_cache_create("store_queue_cache", - sizeof(struct sq_mapping), 0, 0, - NULL, NULL); + sizeof(struct sq_mapping), 0, 0, NULL); if (unlikely(!sq_cache)) return ret; diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index b6a5a338145..a08a4a958ad 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -310,7 +310,7 @@ static int __init pmb_init(void) BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES)); pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0, - SLAB_PANIC, pmb_cache_ctor, NULL); + SLAB_PANIC, pmb_cache_ctor); jump_to_P2(); diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c index 8eb8a7c76ec..7ff0a02f581 100644 --- a/arch/sparc64/mm/tsb.c +++ b/arch/sparc64/mm/tsb.c @@ -262,8 +262,7 @@ void __init pgtable_cache_init(void) tsb_caches[i] = kmem_cache_create(name, size, size, - 0, - NULL, NULL); + 0, NULL); if (!tsb_caches[i]) { prom_printf("Could not create %s cache\n", name); prom_halt(); diff --git a/block/bsg.c b/block/bsg.c index baa04e7adf1..f2992e72b84 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -1043,7 +1043,7 @@ static int __init bsg_init(void) dev_t devid; bsg_cmd_cachep = kmem_cache_create("bsg_cmd", - sizeof(struct bsg_command), 0, 0, NULL, NULL); + sizeof(struct bsg_command), 0, 0, NULL); if (!bsg_cmd_cachep) { printk(KERN_ERR "bsg: failed creating slab cache\n"); return -ENOMEM; diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index d7cadf30416..66056ca5e63 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -3698,13 +3698,13 @@ int __init blk_dev_init(void) panic("Failed to create kblockd\n"); request_cachep = kmem_cache_create("blkdev_requests", - sizeof(struct request), 0, SLAB_PANIC, NULL, NULL); + sizeof(struct request), 0, SLAB_PANIC, NULL); requestq_cachep = kmem_cache_create("blkdev_queue", - sizeof(request_queue_t), 0, SLAB_PANIC, NULL, NULL); + sizeof(request_queue_t), 0, SLAB_PANIC, NULL); iocontext_cachep = kmem_cache_create("blkdev_ioc", - sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL); + sizeof(struct io_context), 0, SLAB_PANIC, NULL); for_each_possible_cpu(i) INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i)); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 2e7ba615d76..00d53c2fd1e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1098,7 +1098,7 @@ void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) acpi_status acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) { - *cache = kmem_cache_create(name, size, 0, 0, NULL, NULL); + *cache = kmem_cache_create(name, size, 0, 0, NULL); if (*cache == NULL) return AE_ERROR; else diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 478489c568a..4f598270fa3 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -257,9 +257,9 @@ aoeblk_exit(void) int __init aoeblk_init(void) { - buf_pool_cache = kmem_cache_create("aoe_bufs", + buf_pool_cache = kmem_cache_create("aoe_bufs", sizeof(struct buf), - 0, 0, NULL, NULL); + 0, 0, NULL); if (buf_pool_cache == NULL) return -ENOMEM; diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 93362eed94e..3a9d7e2d4de 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -1729,7 +1729,7 @@ static int __init ether1394_init_module(void) packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!packet_task_cache) return -ENOMEM; diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 6b8faca02f8..bc547f1d34b 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2998,7 +2998,6 @@ static int __init ib_mad_init_module(void) sizeof(struct ib_mad_private), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); if (!ib_mad_cache) { printk(KERN_ERR PFX "Couldn't create ib_mad cache\n"); diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c index 36620a22413..cfdacb1ec27 100644 --- a/drivers/infiniband/hw/amso1100/c2_vq.c +++ b/drivers/infiniband/hw/amso1100/c2_vq.c @@ -85,7 +85,7 @@ int vq_init(struct c2_dev *c2dev) (char) ('0' + c2dev->devnum)); c2dev->host_msg_cache = kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (c2dev->host_msg_cache == NULL) { return -ENOMEM; } diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c index e53a97af126..97d108634c5 100644 --- a/drivers/infiniband/hw/ehca/ehca_av.c +++ b/drivers/infiniband/hw/ehca/ehca_av.c @@ -259,7 +259,7 @@ int ehca_init_av_cache(void) av_cache = kmem_cache_create("ehca_cache_av", sizeof(struct ehca_av), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!av_cache) return -ENOMEM; return 0; diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 9e87883b561..1e8ca3fca4a 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -387,7 +387,7 @@ int ehca_init_cq_cache(void) cq_cache = kmem_cache_create("ehca_cache_cq", sizeof(struct ehca_cq), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!cq_cache) return -ENOMEM; return 0; diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 36377c6db3d..04c324330b7 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -163,7 +163,7 @@ static int ehca_create_slab_caches(void) ctblk_cache = kmem_cache_create("ehca_cache_ctblk", EHCA_PAGESIZE, H_CB_ALIGNMENT, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!ctblk_cache) { ehca_gen_err("Cannot create ctblk SLAB cache."); ehca_cleanup_mrmw_cache(); diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index 6262c5462d5..9f4c9d46e8e 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -1950,13 +1950,13 @@ int ehca_init_mrmw_cache(void) mr_cache = kmem_cache_create("ehca_cache_mr", sizeof(struct ehca_mr), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!mr_cache) return -ENOMEM; mw_cache = kmem_cache_create("ehca_cache_mw", sizeof(struct ehca_mw), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!mw_cache) { kmem_cache_destroy(mr_cache); mr_cache = NULL; diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c index 79d0591a804..c85312ad292 100644 --- a/drivers/infiniband/hw/ehca/ehca_pd.c +++ b/drivers/infiniband/hw/ehca/ehca_pd.c @@ -100,7 +100,7 @@ int ehca_init_pd_cache(void) pd_cache = kmem_cache_create("ehca_cache_pd", sizeof(struct ehca_pd), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!pd_cache) return -ENOMEM; return 0; diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 48e9ceacd6f..a3146e696c5 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -1760,7 +1760,7 @@ int ehca_init_qp_cache(void) qp_cache = kmem_cache_create("ehca_cache_qp", sizeof(struct ehca_qp), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!qp_cache) return -ENOMEM; return 0; diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index effdee299b0..5db31438027 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -637,7 +637,7 @@ static int __init iser_init(void) ig.desc_cache = kmem_cache_create("iser_descriptors", sizeof (struct iser_desc), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (ig.desc_cache == NULL) return -ENOMEM; diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index b297a6b111a..1199d3f32ac 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c @@ -1332,24 +1332,24 @@ int kvm_mmu_module_init(void) { pte_chain_cache = kmem_cache_create("kvm_pte_chain", sizeof(struct kvm_pte_chain), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!pte_chain_cache) goto nomem; rmap_desc_cache = kmem_cache_create("kvm_rmap_desc", sizeof(struct kvm_rmap_desc), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!rmap_desc_cache) goto nomem; mmu_page_cache = kmem_cache_create("kvm_mmu_page", PAGE_SIZE, - PAGE_SIZE, 0, NULL, NULL); + PAGE_SIZE, 0, NULL); if (!mmu_page_cache) goto nomem; mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header", sizeof(struct kvm_mmu_page), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!mmu_page_header_cache) goto nomem; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 0b66afef2d8..c8dfdb30291 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -951,7 +951,7 @@ static int grow_stripes(raid5_conf_t *conf, int num) conf->active_name = 0; sc = kmem_cache_create(conf->cache_name[conf->active_name], sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!sc) return 1; conf->slab_cache = sc; @@ -1003,7 +1003,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize) /* Step 1 */ sc = kmem_cache_create(conf->cache_name[1-conf->active_name], sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!sc) return -ENOMEM; diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 64a52bd7544..988c8ce47f5 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -1171,8 +1171,7 @@ static int __init i2o_block_init(void) /* Allocate request mempool and slab */ size = sizeof(struct i2o_block_request); i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0, - SLAB_HWCACHE_ALIGN, NULL, - NULL); + SLAB_HWCACHE_ALIGN, NULL); if (!i2o_blk_req_pool.slab) { osm_err("can't init request slab\n"); rc = -ENOMEM; diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 8aff9385613..7c5e29eaf11 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -1149,7 +1149,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) if (ubi_devices_cnt == 0) { ltree_slab = kmem_cache_create("ubi_ltree_slab", sizeof(struct ltree_entry), 0, - 0, <ree_entry_ctor, NULL); + 0, <ree_entry_ctor); if (!ltree_slab) return -ENOMEM; } diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 9de95376209..a5a9b8d8730 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1452,7 +1452,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) if (ubi_devices_cnt == 0) { wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab", sizeof(struct ubi_wl_entry), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!wl_entries_slab) return -ENOMEM; } diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 6a89cefe99b..0c67258fb9e 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -291,7 +291,7 @@ dasd_parse_keyword( char *parsestring ) { dasd_page_cache = kmem_cache_create("dasd_page_cache", PAGE_SIZE, PAGE_SIZE, SLAB_CACHE_DMA, - NULL, NULL ); + NULL); if (!dasd_page_cache) MESSAGE(KERN_WARNING, "%s", "Failed to create slab, " "fixed buffer mode disabled."); diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index a1db9592513..9726261c367 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -259,21 +259,21 @@ zfcp_module_init(void) size = sizeof(struct zfcp_fsf_req_qtcb); align = calc_alignment(size); zfcp_data.fsf_req_qtcb_cache = - kmem_cache_create("zfcp_fsf", size, align, 0, NULL, NULL); + kmem_cache_create("zfcp_fsf", size, align, 0, NULL); if (!zfcp_data.fsf_req_qtcb_cache) goto out; size = sizeof(struct fsf_status_read_buffer); align = calc_alignment(size); zfcp_data.sr_buffer_cache = - kmem_cache_create("zfcp_sr", size, align, 0, NULL, NULL); + kmem_cache_create("zfcp_sr", size, align, 0, NULL); if (!zfcp_data.sr_buffer_cache) goto out_sr_cache; size = sizeof(struct zfcp_gid_pn_data); align = calc_alignment(size); zfcp_data.gid_pn_cache = - kmem_cache_create("zfcp_gid", size, align, 0, NULL, NULL); + kmem_cache_create("zfcp_gid", size, align, 0, NULL); if (!zfcp_data.gid_pn_cache) goto out_gid_cache; diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 1c0d7578e79..b8c6810090d 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -462,7 +462,7 @@ static int asd_create_global_caches(void) sizeof(struct asd_dma_tok), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!asd_dma_token_cache) { asd_printk("couldn't create dma token cache\n"); return -ENOMEM; @@ -474,7 +474,7 @@ static int asd_create_global_caches(void) sizeof(struct asd_ascb), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!asd_ascb_cache) { asd_printk("couldn't create ascb cache\n"); goto Err; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 965698c8b7b..1396c83b0c9 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -292,7 +292,7 @@ EXPORT_SYMBOL_GPL(sas_domain_release_transport); static int __init sas_class_init(void) { sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN, NULL); if (!sas_task_cache) return -ENOMEM; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index b5a77b0c0de..92376f9dfdd 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2723,7 +2723,7 @@ qla2x00_module_init(void) /* Allocate cache for SRBs. */ srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (srb_cachep == NULL) { printk(KERN_ERR "qla2xxx: Unable to allocate SRB cache...Failing load!\n"); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index e69160a7bc6..b1d565c12c5 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1677,7 +1677,7 @@ static int __init qla4xxx_module_init(void) /* Allocate cache for SRBs. */ srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (srb_cachep == NULL) { printk(KERN_ERR "%s: Unable to allocate SRB cache..." diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a691dda40d2..a5de1a829a7 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -288,7 +288,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) if (!pool->users) { pool->slab = kmem_cache_create(pool->name, sizeof(struct scsi_cmnd), 0, - pool->slab_flags, NULL, NULL); + pool->slab_flags, NULL); if (!pool->slab) goto fail; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 1f5a07bf2a7..da63c544919 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1661,7 +1661,7 @@ int __init scsi_init_queue(void) scsi_io_context_cache = kmem_cache_create("scsi_io_context", sizeof(struct scsi_io_context), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!scsi_io_context_cache) { printk(KERN_ERR "SCSI: can't init scsi io context cache\n"); return -ENOMEM; @@ -1672,7 +1672,7 @@ int __init scsi_init_queue(void) int size = sgp->size * sizeof(struct scatterlist); sgp->slab = kmem_cache_create(sgp->name, size, 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (!sgp->slab) { printk(KERN_ERR "SCSI: can't init sg slab %s\n", sgp->name); diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 2570f48a69c..371b69c110b 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -585,7 +585,7 @@ static int __init scsi_tgt_init(void) scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd", sizeof(struct scsi_tgt_cmd), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!scsi_tgt_cmd_cache) return -ENOMEM; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 76c555a67da..805e5fc5f5d 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -933,7 +933,7 @@ static int __init uhci_hcd_init(void) } uhci_up_cachep = kmem_cache_create("uhci_urb_priv", - sizeof(struct urb_priv), 0, 0, NULL, NULL); + sizeof(struct urb_priv), 0, 0, NULL); if (!uhci_up_cachep) goto up_failed; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 982b773d71e..8f27a9e1c36 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -340,7 +340,7 @@ static int mon_text_open(struct inode *inode, struct file *file) snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp); rp->e_slab = kmem_cache_create(rp->slab_name, sizeof(struct mon_event_text), sizeof(long), 0, - mon_text_ctor, NULL); + mon_text_ctor); if (rp->e_slab == NULL) { rc = -ENOMEM; goto err_slab; diff --git a/fs/adfs/super.c b/fs/adfs/super.c index de2ed5ca335..1c9fd302949 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -234,14 +234,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { adfs_inode_cachep = kmem_cache_create("adfs_inode_cache", sizeof(struct adfs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (adfs_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/affs/super.c b/fs/affs/super.c index 6d0ebc32153..c80191ae205 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -99,7 +99,7 @@ static int init_inodecache(void) sizeof(struct affs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (affs_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/afs/super.c b/fs/afs/super.c index 993cdf1cce3..b8808b40f82 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -89,8 +89,7 @@ int __init afs_fs_init(void) sizeof(struct afs_vnode), 0, SLAB_HWCACHE_ALIGN, - afs_i_init_once, - NULL); + afs_i_init_once); if (!afs_inode_cachep) { printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n"); return ret; diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index a5c5171c282..a4514182768 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -414,7 +414,7 @@ befs_read_inode(struct inode *inode) } /* Initialize the inode cache. Called at fs setup. - * + * * Taken from NFS implementation by Al Viro. */ static int @@ -424,7 +424,7 @@ befs_init_inodecache(void) sizeof (struct befs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (befs_inode_cachep == NULL) { printk(KERN_ERR "befs_init_inodecache: " "Couldn't initalize inode slabcache\n"); diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 58c7bd9f530..f346eb14e86 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -250,14 +250,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag inode_init_once(&bi->vfs_inode); } - + static int init_inodecache(void) { bfs_inode_cachep = kmem_cache_create("bfs_inode_cache", sizeof(struct bfs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (bfs_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/bio.c b/fs/bio.c index 33e46340a76..0d2c2d38b7b 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1187,7 +1187,7 @@ static void __init biovec_init_slabs(void) size = bvs->nr_vecs * sizeof(struct bio_vec); bvs->slab = kmem_cache_create(bvs->name, size, 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); } } diff --git a/fs/block_dev.c b/fs/block_dev.c index 3635315e3b9..2980eabe577 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -517,7 +517,7 @@ void __init bdev_cache_init(void) bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode), 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD|SLAB_PANIC), - init_once, NULL); + init_once); err = register_filesystem(&bd_type); if (err) panic("Cannot register bdev pseudo-fs"); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1fd0dc85f53..cabb6a55d7d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -719,7 +719,7 @@ cifs_init_inodecache(void) sizeof (struct cifsInodeInfo), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - cifs_init_once, NULL); + cifs_init_once); if (cifs_inode_cachep == NULL) return -ENOMEM; @@ -748,7 +748,7 @@ cifs_init_request_bufs(void) cifs_req_cachep = kmem_cache_create("cifs_request", CIFSMaxBufSize + MAX_CIFS_HDR_SIZE, 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (cifs_req_cachep == NULL) return -ENOMEM; @@ -776,7 +776,7 @@ cifs_init_request_bufs(void) alloc of large cifs buffers even when page debugging is on */ cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (cifs_sm_req_cachep == NULL) { mempool_destroy(cifs_req_poolp); kmem_cache_destroy(cifs_req_cachep); @@ -817,7 +817,7 @@ cifs_init_mids(void) { cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", sizeof (struct mid_q_entry), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (cifs_mid_cachep == NULL) return -ENOMEM; @@ -830,7 +830,7 @@ cifs_init_mids(void) cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs", sizeof (struct oplock_q_entry), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (cifs_oplock_cachep == NULL) { mempool_destroy(cifs_mid_poolp); kmem_cache_destroy(cifs_mid_cachep); diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 6771a4271e3..342f4e0d582 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -64,13 +64,13 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag inode_init_once(&ei->vfs_inode); } - + int coda_init_inodecache(void) { coda_inode_cachep = kmem_cache_create("coda_inode_cache", sizeof(struct coda_inode_info), 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, - init_once, NULL); + init_once); if (coda_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index b00d962de83..871b0cb6183 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -136,7 +136,7 @@ static int __init configfs_init(void) configfs_dir_cachep = kmem_cache_create("configfs_dir_cache", sizeof(struct configfs_dirent), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!configfs_dir_cachep) goto out; diff --git a/fs/dcache.c b/fs/dcache.c index cb9d05056b5..678d39deb60 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2165,10 +2165,10 @@ void __init vfs_caches_init(unsigned long mempages) mempages -= reserve; names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); dcache_init(mempages); inode_init(mempages); diff --git a/fs/dcookies.c b/fs/dcookies.c index 21af1629f9b..c1208f53bd7 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -205,7 +205,7 @@ static int dcookie_init(void) dcookie_cache = kmem_cache_create("dcookie_cache", sizeof(struct dcookie_struct), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!dcookie_cache) goto out; diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 0553a6158dc..dd362739d29 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -1449,7 +1449,7 @@ int dlm_lowcomms_start(void) error = -ENOMEM; con_cache = kmem_cache_create("dlm_conn", sizeof(struct connection), __alignof__(struct connection), 0, - NULL, NULL); + NULL); if (!con_cache) goto out; diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c index fb9e2ee998a..ecf0e5cb203 100644 --- a/fs/dlm/memory.c +++ b/fs/dlm/memory.c @@ -23,7 +23,7 @@ int dlm_memory_init(void) int ret = 0; lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb), - __alignof__(struct dlm_lkb), 0, NULL, NULL); + __alignof__(struct dlm_lkb), 0, NULL); if (!lkb_cache) ret = -ENOMEM; return ret; diff --git a/fs/dnotify.c b/fs/dnotify.c index 936409fcd93..28d01ed66de 100644 --- a/fs/dnotify.c +++ b/fs/dnotify.c @@ -176,7 +176,7 @@ EXPORT_SYMBOL_GPL(dnotify_parent); static int __init dnotify_init(void) { dn_cache = kmem_cache_create("dnotify_cache", - sizeof(struct dnotify_struct), 0, SLAB_PANIC, NULL, NULL); + sizeof(struct dnotify_struct), 0, SLAB_PANIC, NULL); return 0; } diff --git a/fs/dquot.c b/fs/dquot.c index 7e273151f58..de9a29f64ff 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -1848,11 +1848,11 @@ static int __init dquot_init(void) register_sysctl_table(sys_table); - dquot_cachep = kmem_cache_create("dquot", + dquot_cachep = kmem_cache_create("dquot", sizeof(struct dquot), sizeof(unsigned long) * 4, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD|SLAB_PANIC), - NULL, NULL); + NULL); order = 0; dquot_hash = (struct hlist_head *)__get_free_pages(GFP_ATOMIC, order); diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 02ca6f1e55d..e557a676692 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -677,7 +677,7 @@ static int ecryptfs_init_kmem_caches(void) info = &ecryptfs_cache_infos[i]; *(info->cache) = kmem_cache_create(info->name, info->size, - 0, SLAB_HWCACHE_ALIGN, info->ctor, NULL); + 0, SLAB_HWCACHE_ALIGN, info->ctor); if (!*(info->cache)) { ecryptfs_free_kmem_caches(); ecryptfs_printk(KERN_WARNING, "%s: " diff --git a/fs/efs/super.c b/fs/efs/super.c index d360c81f3a7..ce4acb8ff81 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -75,13 +75,13 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { efs_inode_cachep = kmem_cache_create("efs_inode_cache", sizeof(struct efs_inode_info), 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, - init_once, NULL); + init_once); if (efs_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 0b73cd45a06..77b9953624f 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1324,12 +1324,12 @@ static int __init eventpoll_init(void) /* Allocates slab cache used to allocate "struct epitem" items */ epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem), 0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC, - NULL, NULL); + NULL); /* Allocates slab cache used to allocate "struct eppoll_entry" */ pwq_cache = kmem_cache_create("eventpoll_pwq", sizeof(struct eppoll_entry), 0, - EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL); + EPI_SLAB_DEBUG|SLAB_PANIC, NULL); return 0; } diff --git a/fs/ext2/super.c b/fs/ext2/super.c index a6b1072daea..68579a0ed3f 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -167,14 +167,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag #endif inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { ext2_inode_cachep = kmem_cache_create("ext2_inode_cache", sizeof(struct ext2_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (ext2_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 4f84dc86628..f0614e3f1fe 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -490,7 +490,7 @@ static int init_inodecache(void) sizeof(struct ext3_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (ext3_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6dcbb28dc06..75adbb64e02 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -541,7 +541,7 @@ static int init_inodecache(void) sizeof(struct ext4_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (ext4_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 3c9c8a15ec7..be6f89b152c 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -48,7 +48,7 @@ int __init fat_cache_init(void) fat_cache_cachep = kmem_cache_create("fat_cache", sizeof(struct fat_cache), 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, - init_once, NULL); + init_once); if (fat_cache_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 0a7ddb39a59..4baa5f20536 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -514,7 +514,7 @@ static int __init fat_init_inodecache(void) sizeof(struct msdos_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (fat_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/fcntl.c b/fs/fcntl.c index 3f22e9f4f69..78b2ff04405 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -638,7 +638,7 @@ EXPORT_SYMBOL(kill_fasync); static int __init fasync_init(void) { fasync_cache = kmem_cache_create("fasync_cache", - sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL, NULL); + sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL); return 0; } diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 647d600f0bc..4f95572d272 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -263,8 +263,8 @@ vxfs_init(void) int rv; vxfs_inode_cachep = kmem_cache_create("vxfs_inode", - sizeof(struct vxfs_inode_info), 0, - SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL); + sizeof(struct vxfs_inode_info), 0, + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); if (!vxfs_inode_cachep) return -ENOMEM; rv = register_filesystem(&vxfs_fs_type); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 357764d85ff..3ad22beb24c 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1044,7 +1044,7 @@ int __init fuse_dev_init(void) int err = -ENOMEM; fuse_req_cachep = kmem_cache_create("fuse_request", sizeof(struct fuse_req), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!fuse_req_cachep) goto out; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index cc5efc13496..5448f625ab5 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -706,7 +706,7 @@ static int __init fuse_fs_init(void) fuse_inode_cachep = kmem_cache_create("fuse_inode", sizeof(struct fuse_inode), 0, SLAB_HWCACHE_ALIGN, - fuse_inode_init_once, NULL); + fuse_inode_init_once); err = -ENOMEM; if (!fuse_inode_cachep) goto out_unreg2; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 787a0edef10..d5d4e68b880 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -72,7 +72,7 @@ static int __init init_gfs2_fs(void) gfs2_glock_cachep = kmem_cache_create("gfs2_glock", sizeof(struct gfs2_glock), 0, 0, - gfs2_init_glock_once, NULL); + gfs2_init_glock_once); if (!gfs2_glock_cachep) goto fail; @@ -80,13 +80,13 @@ static int __init init_gfs2_fs(void) sizeof(struct gfs2_inode), 0, SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD, - gfs2_init_inode_once, NULL); + gfs2_init_inode_once); if (!gfs2_inode_cachep) goto fail; gfs2_bufdata_cachep = kmem_cache_create("gfs2_bufdata", sizeof(struct gfs2_bufdata), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!gfs2_bufdata_cachep) goto fail; diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 92cf8751e42..6c5f92dfb50 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -443,7 +443,7 @@ static int __init init_hfs_fs(void) hfs_inode_cachep = kmem_cache_create("hfs_inode_cache", sizeof(struct hfs_inode_info), 0, SLAB_HWCACHE_ALIGN, - hfs_init_once, NULL); + hfs_init_once); if (!hfs_inode_cachep) return -ENOMEM; err = register_filesystem(&hfs_fs_type); diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 6d87a2a9534..7b0f2e5a44e 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -479,7 +479,7 @@ static int __init init_hfsplus_fs(void) hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache", HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN, - hfsplus_init_once, NULL); + hfsplus_init_once); if (!hfsplus_inode_cachep) return -ENOMEM; err = register_filesystem(&hfsplus_fs_type); diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 29cc34abb2e..89612ee7c80 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -181,14 +181,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag mutex_init(&ei->i_parent_mutex); inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache", sizeof(struct hpfs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (hpfs_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index d145cb79c30..c848a191525 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -848,7 +848,7 @@ static int __init init_hugetlbfs_fs(void) hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache", sizeof(struct hugetlbfs_inode_info), - 0, 0, init_once, NULL); + 0, 0, init_once); if (hugetlbfs_inode_cachep == NULL) return -ENOMEM; diff --git a/fs/inode.c b/fs/inode.c index 320e088d0b2..29f5068f819 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1388,8 +1388,7 @@ void __init inode_init(unsigned long mempages) 0, (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC| SLAB_MEM_SPREAD), - init_once, - NULL); + init_once); register_shrinker(&icache_shrinker); /* Hash may have been set up in inode_init_early */ diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 9f2224f65a1..9bf2f6c09df 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -716,10 +716,10 @@ static int __init inotify_user_setup(void) watch_cachep = kmem_cache_create("inotify_watch_cache", sizeof(struct inotify_user_watch), - 0, SLAB_PANIC, NULL, NULL); + 0, SLAB_PANIC, NULL); event_cachep = kmem_cache_create("inotify_event_cache", sizeof(struct inotify_kernel_event), - 0, SLAB_PANIC, NULL, NULL); + 0, SLAB_PANIC, NULL); return 0; } diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 4f5418be059..95c72aa8186 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -86,7 +86,7 @@ static int init_inodecache(void) sizeof(struct iso_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (isofs_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 46fe7439fb9..06ab3c10b1b 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1668,7 +1668,7 @@ static int journal_create_jbd_slab(size_t slab_size) * boundary. */ jbd_slab[i] = kmem_cache_create(jbd_slab_names[i], - slab_size, slab_size, 0, NULL, NULL); + slab_size, slab_size, 0, NULL); if (!jbd_slab[i]) { printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n"); return -ENOMEM; @@ -1711,8 +1711,7 @@ static int journal_init_journal_head_cache(void) sizeof(struct journal_head), 0, /* offset */ 0, /* flags */ - NULL, /* ctor */ - NULL); /* dtor */ + NULL); /* ctor */ retval = 0; if (journal_head_cache == 0) { retval = -ENOMEM; @@ -2008,8 +2007,7 @@ static int __init journal_init_handle_cache(void) sizeof(handle_t), 0, /* offset */ 0, /* flags */ - NULL, /* ctor */ - NULL); /* dtor */ + NULL); /* ctor */ if (jbd_handle_cache == NULL) { printk(KERN_EMERG "JBD: failed to create handle cache\n"); return -ENOMEM; diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index 8db2fa25170..62e13c8db13 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -170,13 +170,13 @@ int __init journal_init_revoke_caches(void) { revoke_record_cache = kmem_cache_create("revoke_record", sizeof(struct jbd_revoke_record_s), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN, NULL); if (revoke_record_cache == 0) return -ENOMEM; revoke_table_cache = kmem_cache_create("revoke_table", sizeof(struct jbd_revoke_table_s), - 0, 0, NULL, NULL); + 0, 0, NULL); if (revoke_table_cache == 0) { kmem_cache_destroy(revoke_record_cache); revoke_record_cache = NULL; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index f290cb7cb83..f37324aee81 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1680,7 +1680,7 @@ static int jbd2_journal_create_jbd_slab(size_t slab_size) * boundary. */ jbd_slab[i] = kmem_cache_create(jbd_slab_names[i], - slab_size, slab_size, 0, NULL, NULL); + slab_size, slab_size, 0, NULL); if (!jbd_slab[i]) { printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n"); return -ENOMEM; @@ -1723,8 +1723,7 @@ static int journal_init_jbd2_journal_head_cache(void) sizeof(struct journal_head), 0, /* offset */ 0, /* flags */ - NULL, /* ctor */ - NULL); /* dtor */ + NULL); /* ctor */ retval = 0; if (jbd2_journal_head_cache == 0) { retval = -ENOMEM; @@ -2006,8 +2005,7 @@ static int __init journal_init_handle_cache(void) sizeof(handle_t), 0, /* offset */ 0, /* flags */ - NULL, /* ctor */ - NULL); /* dtor */ + NULL); /* ctor */ if (jbd2_handle_cache == NULL) { printk(KERN_EMERG "JBD: failed to create handle cache\n"); return -ENOMEM; diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 28cac049a56..01d88975e0c 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -171,13 +171,13 @@ int __init jbd2_journal_init_revoke_caches(void) { jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record", sizeof(struct jbd2_revoke_record_s), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN, NULL); if (jbd2_revoke_record_cache == 0) return -ENOMEM; jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table", sizeof(struct jbd2_revoke_table_s), - 0, 0, NULL, NULL); + 0, 0, NULL); if (jbd2_revoke_table_cache == 0) { kmem_cache_destroy(jbd2_revoke_record_cache); jbd2_revoke_record_cache = NULL; diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 35c1a5e30ba..f9211252b5f 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -33,56 +33,56 @@ int __init jffs2_create_slab_caches(void) { full_dnode_slab = kmem_cache_create("jffs2_full_dnode", sizeof(struct jffs2_full_dnode), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!full_dnode_slab) goto err; raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", sizeof(struct jffs2_raw_dirent), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!raw_dirent_slab) goto err; raw_inode_slab = kmem_cache_create("jffs2_raw_inode", sizeof(struct jffs2_raw_inode), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!raw_inode_slab) goto err; tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", sizeof(struct jffs2_tmp_dnode_info), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!tmp_dnode_info_slab) goto err; raw_node_ref_slab = kmem_cache_create("jffs2_refblock", sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!raw_node_ref_slab) goto err; node_frag_slab = kmem_cache_create("jffs2_node_frag", sizeof(struct jffs2_node_frag), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!node_frag_slab) goto err; inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!inode_cache_slab) goto err; #ifdef CONFIG_JFFS2_FS_XATTR xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum", sizeof(struct jffs2_xattr_datum), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!xattr_datum_cache) goto err; xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref", sizeof(struct jffs2_xattr_ref), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!xattr_ref_cache) goto err; #endif diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index e220d3bd610..be2b70c2ec1 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -192,7 +192,7 @@ static int __init init_jffs2_fs(void) sizeof(struct jffs2_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - jffs2_i_init_once, NULL); + jffs2_i_init_once); if (!jffs2_inode_cachep) { printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n"); return -ENOMEM; diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 77c7f1129dd..62e96be02ac 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -213,7 +213,7 @@ int __init metapage_init(void) * Allocate the metapage structures */ metapage_cache = kmem_cache_create("jfs_mp", sizeof(struct metapage), - 0, 0, init_once, NULL); + 0, 0, init_once); if (metapage_cache == NULL) return -ENOMEM; diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 929fceca799..4b372f55065 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -776,7 +776,7 @@ static int __init init_jfs_fs(void) jfs_inode_cachep = kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, - init_once, NULL); + init_once); if (jfs_inode_cachep == NULL) return -ENOMEM; diff --git a/fs/locks.c b/fs/locks.c index 4f2d749ac62..31051063724 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2276,7 +2276,7 @@ static int __init filelock_init(void) { filelock_cache = kmem_cache_create("file_lock_cache", sizeof(struct file_lock), 0, SLAB_PANIC, - init_once, NULL); + init_once); return 0; } diff --git a/fs/mbcache.c b/fs/mbcache.c index fbb1d02f879..1046cbefbfb 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -292,7 +292,7 @@ mb_cache_create(const char *name, struct mb_cache_op *cache_op, INIT_LIST_HEAD(&cache->c_indexes_hash[m][n]); } cache->c_entry_cache = kmem_cache_create(name, entry_size, 0, - SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL); + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); if (!cache->c_entry_cache) goto fail; diff --git a/fs/minix/inode.c b/fs/minix/inode.c index be4044614ac..43668d7d668 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -75,14 +75,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { minix_inode_cachep = kmem_cache_create("minix_inode_cache", sizeof(struct minix_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (minix_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/namespace.c b/fs/namespace.c index 4198003d7e1..ddbda13c2d3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1801,7 +1801,7 @@ void __init mnt_init(unsigned long mempages) init_rwsem(&namespace_sem); mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount), - 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index cf06eb9f050..7f8536dbded 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -63,14 +63,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag mutex_init(&ei->open_mutex); inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { ncp_inode_cachep = kmem_cache_create("ncp_inode_cache", sizeof(struct ncp_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (ncp_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index a5c82b6f3b4..fcf4d384610 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -875,7 +875,7 @@ int __init nfs_init_directcache(void) sizeof(struct nfs_direct_req), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - NULL, NULL); + NULL); if (nfs_direct_cachep == NULL) return -ENOMEM; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 3d9fccf4ef9..bca6cdcb9f0 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1165,14 +1165,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag nfsi->npages = 0; nfs4_init_once(nfsi); } - + static int __init nfs_init_inodecache(void) { nfs_inode_cachep = kmem_cache_create("nfs_inode_cache", sizeof(struct nfs_inode), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (nfs_inode_cachep == NULL) return -ENOMEM; diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index f56dae5216f..345bb9b4765 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -442,7 +442,7 @@ int __init nfs_init_nfspagecache(void) nfs_page_cachep = kmem_cache_create("nfs_page", sizeof(struct nfs_page), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (nfs_page_cachep == NULL) return -ENOMEM; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 6ae2e58ed05..19e05633f4e 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -598,7 +598,7 @@ int __init nfs_init_readpagecache(void) nfs_rdata_cachep = kmem_cache_create("nfs_read_data", sizeof(struct nfs_read_data), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (nfs_rdata_cachep == NULL) return -ENOMEM; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 73ac992ece8..ef97e0c0f5b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1467,7 +1467,7 @@ int __init nfs_init_writepagecache(void) nfs_wdata_cachep = kmem_cache_create("nfs_write_data", sizeof(struct nfs_write_data), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (nfs_wdata_cachep == NULL) return -ENOMEM; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6284807bd37..3f559700788 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1032,19 +1032,19 @@ static int nfsd4_init_slabs(void) { stateowner_slab = kmem_cache_create("nfsd4_stateowners", - sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL); + sizeof(struct nfs4_stateowner), 0, 0, NULL); if (stateowner_slab == NULL) goto out_nomem; file_slab = kmem_cache_create("nfsd4_files", - sizeof(struct nfs4_file), 0, 0, NULL, NULL); + sizeof(struct nfs4_file), 0, 0, NULL); if (file_slab == NULL) goto out_nomem; stateid_slab = kmem_cache_create("nfsd4_stateids", - sizeof(struct nfs4_stateid), 0, 0, NULL, NULL); + sizeof(struct nfs4_stateid), 0, 0, NULL); if (stateid_slab == NULL) goto out_nomem; deleg_slab = kmem_cache_create("nfsd4_delegations", - sizeof(struct nfs4_delegation), 0, 0, NULL, NULL); + sizeof(struct nfs4_delegation), 0, 0, NULL); if (deleg_slab == NULL) goto out_nomem; return 0; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 4566b918255..90c4e3a2970 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -3143,7 +3143,7 @@ static int __init init_ntfs_fs(void) ntfs_index_ctx_cache = kmem_cache_create(ntfs_index_ctx_cache_name, sizeof(ntfs_index_context), 0 /* offset */, - SLAB_HWCACHE_ALIGN, NULL /* ctor */, NULL /* dtor */); + SLAB_HWCACHE_ALIGN, NULL /* ctor */); if (!ntfs_index_ctx_cache) { printk(KERN_CRIT "NTFS: Failed to create %s!\n", ntfs_index_ctx_cache_name); @@ -3151,7 +3151,7 @@ static int __init init_ntfs_fs(void) } ntfs_attr_ctx_cache = kmem_cache_create(ntfs_attr_ctx_cache_name, sizeof(ntfs_attr_search_ctx), 0 /* offset */, - SLAB_HWCACHE_ALIGN, NULL /* ctor */, NULL /* dtor */); + SLAB_HWCACHE_ALIGN, NULL /* ctor */); if (!ntfs_attr_ctx_cache) { printk(KERN_CRIT "NTFS: Failed to create %s!\n", ntfs_attr_ctx_cache_name); @@ -3160,7 +3160,7 @@ static int __init init_ntfs_fs(void) ntfs_name_cache = kmem_cache_create(ntfs_name_cache_name, (NTFS_MAX_NAME_LEN+1) * sizeof(ntfschar), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (!ntfs_name_cache) { printk(KERN_CRIT "NTFS: Failed to create %s!\n", ntfs_name_cache_name); @@ -3169,7 +3169,7 @@ static int __init init_ntfs_fs(void) ntfs_inode_cache = kmem_cache_create(ntfs_inode_cache_name, sizeof(ntfs_inode), 0, - SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL); + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); if (!ntfs_inode_cache) { printk(KERN_CRIT "NTFS: Failed to create %s!\n", ntfs_inode_cache_name); @@ -3179,7 +3179,7 @@ static int __init init_ntfs_fs(void) ntfs_big_inode_cache = kmem_cache_create(ntfs_big_inode_cache_name, sizeof(big_ntfs_inode), 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, - ntfs_big_inode_init_once, NULL); + ntfs_big_inode_init_once); if (!ntfs_big_inode_cache) { printk(KERN_CRIT "NTFS: Failed to create %s!\n", ntfs_big_inode_cache_name); diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index fd8cb1badc9..7418dc83de1 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -592,7 +592,7 @@ static int __init init_dlmfs_fs(void) sizeof(struct dlmfs_inode_private), 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - dlmfs_init_once, NULL); + dlmfs_init_once); if (!dlmfs_inode_cache) return -ENOMEM; cleanup_inode = 1; diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 65b2b9b9268..62e4a7daa28 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -510,7 +510,7 @@ int dlm_init_mle_cache(void) dlm_mle_cache = kmem_cache_create("dlm_mle_cache", sizeof(struct dlm_master_list_entry), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (dlm_mle_cache == NULL) return -ENOMEM; return 0; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 3a5a1ed09ac..200c7d4790d 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -984,7 +984,7 @@ static int ocfs2_initialize_mem_caches(void) 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - ocfs2_inode_init_once, NULL); + ocfs2_inode_init_once); if (!ocfs2_inode_cachep) return -ENOMEM; diff --git a/fs/ocfs2/uptodate.c b/fs/ocfs2/uptodate.c index 39814b900fc..4da8851f2b2 100644 --- a/fs/ocfs2/uptodate.c +++ b/fs/ocfs2/uptodate.c @@ -548,7 +548,7 @@ int __init init_ocfs2_uptodate_cache(void) { ocfs2_uptodate_cachep = kmem_cache_create("ocfs2_uptodate", sizeof(struct ocfs2_meta_cache_item), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN, NULL); if (!ocfs2_uptodate_cachep) return -ENOMEM; diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index e62397341c3..dd86be2aa6c 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -431,7 +431,7 @@ static int __init init_openprom_fs(void) 0, (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD), - op_inode_init_once, NULL); + op_inode_init_once); if (!op_inode_cachep) return -ENOMEM; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index dd28e86ab42..94e2c1adf18 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -112,14 +112,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag inode_init_once(&ei->vfs_inode); } - + int __init proc_init_inodecache(void) { proc_inode_cachep = kmem_cache_create("proc_inode_cache", sizeof(struct proc_inode), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (proc_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 8d256eb1181..1bc8d873a9e 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -545,7 +545,7 @@ static int init_inodecache(void) sizeof(struct qnx4_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (qnx4_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 5a93cfe1a03..5b68dd3f191 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -527,7 +527,7 @@ static int init_inodecache(void) reiserfs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (reiserfs_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 2284e03342c..dae7945f90e 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -572,14 +572,14 @@ static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { romfs_inode_cachep = kmem_cache_create("romfs_inode_cache", sizeof(struct romfs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (romfs_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 6724a6cf01f..73d1450a95d 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -73,14 +73,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { smb_inode_cachep = kmem_cache_create("smb_inode_cache", sizeof(struct smb_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (smb_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c index 3f54a0f80fa..ca4b2d59c0c 100644 --- a/fs/smbfs/request.c +++ b/fs/smbfs/request.c @@ -40,7 +40,7 @@ int smb_init_request_cache(void) req_cachep = kmem_cache_create("smb_request", sizeof(struct smb_request), 0, SMB_SLAB_DEBUG | SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (req_cachep == NULL) return -ENOMEM; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 60714d075c2..fbc7b65fe26 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -86,7 +86,7 @@ int __init sysfs_init(void) sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", sizeof(struct sysfs_dirent), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!sysfs_dir_cachep) goto out; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 56441169339..7c4e5d302ab 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -342,7 +342,7 @@ int __init sysv_init_icache(void) sysv_inode_cachep = kmem_cache_create("sysv_inode_cache", sizeof(struct sysv_inode_info), 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, - init_once, NULL); + init_once); if (!sysv_inode_cachep) return -ENOMEM; return 0; diff --git a/fs/udf/super.c b/fs/udf/super.c index 911387aa181..72097ee6b75 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -149,7 +149,7 @@ static int init_inodecache(void) sizeof(struct udf_inode_info), 0, (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (udf_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 2b3011689e8..73402c5eeb8 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1240,14 +1240,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { ufs_inode_cachep = kmem_cache_create("ufs_inode_cache", sizeof(struct ufs_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (ufs_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index 4b6470cf87f..b4acc7f3c37 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h @@ -74,14 +74,14 @@ extern void kmem_free(void *, size_t); static inline kmem_zone_t * kmem_zone_init(int size, char *zone_name) { - return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL); + return kmem_cache_create(zone_name, size, 0, 0, NULL); } static inline kmem_zone_t * kmem_zone_init_flags(int size, char *zone_name, unsigned long flags, void (*construct)(void *, kmem_zone_t *, unsigned long)) { - return kmem_cache_create(zone_name, size, 0, flags, construct, NULL); + return kmem_cache_create(zone_name, size, 0, flags, construct); } static inline void diff --git a/include/linux/i2o.h b/include/linux/i2o.h index 333a370a3bd..9752307d16b 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -946,8 +946,7 @@ static inline int i2o_pool_alloc(struct i2o_pool *pool, const char *name, strcpy(pool->name, name); pool->slab = - kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL, - NULL); + kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL); if (!pool->slab) goto free_name; diff --git a/include/linux/slab.h b/include/linux/slab.h index 0e1d0daef6a..7d0ecc1659f 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -51,7 +51,6 @@ int slab_is_available(void); struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, unsigned long, - void (*)(void *, struct kmem_cache *, unsigned long), void (*)(void *, struct kmem_cache *, unsigned long)); void kmem_cache_destroy(struct kmem_cache *); int kmem_cache_shrink(struct kmem_cache *); @@ -70,7 +69,7 @@ int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr); */ #define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\ sizeof(struct __struct), __alignof__(struct __struct),\ - (__flags), NULL, NULL) + (__flags), NULL) /* * The largest kmalloc size supported by the slab allocators is diff --git a/ipc/mqueue.c b/ipc/mqueue.c index a242c83d89d..145d5a0d299 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1253,7 +1253,7 @@ static int __init init_mqueue_fs(void) mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache", sizeof(struct mqueue_inode_info), 0, - SLAB_HWCACHE_ALIGN, init_once, NULL); + SLAB_HWCACHE_ALIGN, init_once); if (mqueue_inode_cachep == NULL) return -ENOMEM; diff --git a/kernel/fork.c b/kernel/fork.c index 46983899822..7332e236d36 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -137,7 +137,7 @@ void __init fork_init(unsigned long mempages) /* create a slab on which task_structs can be allocated */ task_struct_cachep = kmem_cache_create("task_struct", sizeof(struct task_struct), - ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL, NULL); + ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL); #endif /* @@ -1446,22 +1446,22 @@ void __init proc_caches_init(void) sighand_cachep = kmem_cache_create("sighand_cache", sizeof(struct sighand_struct), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU, - sighand_ctor, NULL); + sighand_ctor); signal_cachep = kmem_cache_create("signal_cache", sizeof(struct signal_struct), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); - files_cachep = kmem_cache_create("files_cache", + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + files_cachep = kmem_cache_create("files_cache", sizeof(struct files_struct), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); - fs_cachep = kmem_cache_create("fs_cache", + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + fs_cachep = kmem_cache_create("fs_cache", sizeof(struct fs_struct), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); vm_area_cachep = kmem_cache_create("vm_area_struct", sizeof(struct vm_area_struct), 0, - SLAB_PANIC, NULL, NULL); + SLAB_PANIC, NULL); mm_cachep = kmem_cache_create("mm_struct", sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); } /* diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 10f0bbba382..a4fb7d46971 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -193,7 +193,7 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags, static int __init nsproxy_cache_init(void) { nsproxy_cachep = kmem_cache_create("nsproxy", sizeof(struct nsproxy), - 0, SLAB_PANIC, NULL, NULL); + 0, SLAB_PANIC, NULL); return 0; } diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index 329ce017207..55b3761edaa 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -241,7 +241,7 @@ static __init int init_posix_timers(void) register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic); posix_timers_cache = kmem_cache_create("posix_timers_cache", - sizeof (struct k_itimer), 0, 0, NULL, NULL); + sizeof (struct k_itimer), 0, 0, NULL); idr_init(&posix_timers_id); return 0; } diff --git a/kernel/user.c b/kernel/user.c index 98b82507797..e7d11cef699 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -208,7 +208,7 @@ static int __init uid_cache_init(void) int n; uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct), - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); for(n = 0; n < UIDHASH_SZ; ++n) INIT_LIST_HEAD(init_user_ns.uidhash_table + n); diff --git a/lib/idr.c b/lib/idr.c index 5ca67b3cfd3..ffd61941e75 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -590,7 +590,7 @@ static int init_id_cache(void) { if (!idr_layer_cache) idr_layer_cache = kmem_cache_create("idr_layer_cache", - sizeof(struct idr_layer), 0, 0, idr_cache_ctor, NULL); + sizeof(struct idr_layer), 0, 0, idr_cache_ctor); return 0; } diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 9927cca14cb..514efb200be 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -1021,7 +1021,7 @@ void __init radix_tree_init(void) { radix_tree_node_cachep = kmem_cache_create("radix_tree_node", sizeof(struct radix_tree_node), 0, - SLAB_PANIC, radix_tree_node_ctor, NULL); + SLAB_PANIC, radix_tree_node_ctor); radix_tree_init_maxindex(); hotcpu_notifier(radix_tree_callback, 0); } diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 9f4e9b95e8f..71b84b45154 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1605,11 +1605,11 @@ void __init numa_policy_init(void) policy_cache = kmem_cache_create("numa_policy", sizeof(struct mempolicy), - 0, SLAB_PANIC, NULL, NULL); + 0, SLAB_PANIC, NULL); sn_cache = kmem_cache_create("shared_policy_node", sizeof(struct sp_node), - 0, SLAB_PANIC, NULL, NULL); + 0, SLAB_PANIC, NULL); /* * Set interleaving policy for system init. Interleaving is only diff --git a/mm/rmap.c b/mm/rmap.c index fede5c7910b..41ac39749ef 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -149,7 +149,7 @@ static void anon_vma_ctor(void *data, struct kmem_cache *cachep, void __init anon_vma_init(void) { anon_vma_cachep = kmem_cache_create("anon_vma", sizeof(struct anon_vma), - 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor, NULL); + 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor); } /* diff --git a/mm/shmem.c b/mm/shmem.c index ad155c7745d..fcd19d323f9 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2322,7 +2322,7 @@ static int init_inodecache(void) { shmem_inode_cachep = kmem_cache_create("shmem_inode_cache", sizeof(struct shmem_inode_info), - 0, 0, init_once, NULL); + 0, 0, init_once); if (shmem_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/mm/slab.c b/mm/slab.c index c3feeaab387..bde271c001b 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1484,7 +1484,7 @@ void __init kmem_cache_init(void) sizes[INDEX_AC].cs_size, ARCH_KMALLOC_MINALIGN, ARCH_KMALLOC_FLAGS|SLAB_PANIC, - NULL, NULL); + NULL); if (INDEX_AC != INDEX_L3) { sizes[INDEX_L3].cs_cachep = @@ -1492,7 +1492,7 @@ void __init kmem_cache_init(void) sizes[INDEX_L3].cs_size, ARCH_KMALLOC_MINALIGN, ARCH_KMALLOC_FLAGS|SLAB_PANIC, - NULL, NULL); + NULL); } slab_early_init = 0; @@ -1510,7 +1510,7 @@ void __init kmem_cache_init(void) sizes->cs_size, ARCH_KMALLOC_MINALIGN, ARCH_KMALLOC_FLAGS|SLAB_PANIC, - NULL, NULL); + NULL); } #ifdef CONFIG_ZONE_DMA sizes->cs_dmacachep = kmem_cache_create( @@ -1519,7 +1519,7 @@ void __init kmem_cache_init(void) ARCH_KMALLOC_MINALIGN, ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA| SLAB_PANIC, - NULL, NULL); + NULL); #endif sizes++; names++; @@ -2101,12 +2101,10 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep) * @align: The required alignment for the objects. * @flags: SLAB flags * @ctor: A constructor for the objects. - * @dtor: A destructor for the objects (not implemented anymore). * * Returns a ptr to the cache on success, NULL on failure. * Cannot be called within a int, but can be interrupted. - * The @ctor is run when new pages are allocated by the cache - * and the @dtor is run before the pages are handed back. + * The @ctor is run when new pages are allocated by the cache. * * @name must be valid until the cache is destroyed. This implies that * the module calling this has to destroy the cache before getting unloaded. @@ -2126,8 +2124,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep) struct kmem_cache * kmem_cache_create (const char *name, size_t size, size_t align, unsigned long flags, - void (*ctor)(void*, struct kmem_cache *, unsigned long), - void (*dtor)(void*, struct kmem_cache *, unsigned long)) + void (*ctor)(void*, struct kmem_cache *, unsigned long)) { size_t left_over, slab_size, ralign; struct kmem_cache *cachep = NULL, *pc; @@ -2136,7 +2133,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, * Sanity checks... these are all serious usage bugs. */ if (!name || in_interrupt() || (size < BYTES_PER_WORD) || - size > KMALLOC_MAX_SIZE || dtor) { + size > KMALLOC_MAX_SIZE) { printk(KERN_ERR "%s: Early error in slab %s\n", __FUNCTION__, name); BUG(); diff --git a/mm/slob.c b/mm/slob.c index c89ef116d7a..d50920ecc02 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -492,8 +492,7 @@ struct kmem_cache { struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, - void (*ctor)(void*, struct kmem_cache *, unsigned long), - void (*dtor)(void*, struct kmem_cache *, unsigned long)) + void (*ctor)(void*, struct kmem_cache *, unsigned long)) { struct kmem_cache *c; diff --git a/mm/slub.c b/mm/slub.c index 322f3a5d72c..9b2d6178d06 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2668,12 +2668,10 @@ static struct kmem_cache *find_mergeable(size_t size, struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, - void (*ctor)(void *, struct kmem_cache *, unsigned long), - void (*dtor)(void *, struct kmem_cache *, unsigned long)) + void (*ctor)(void *, struct kmem_cache *, unsigned long)) { struct kmem_cache *s; - BUG_ON(dtor); down_write(&slub_lock); s = find_mergeable(size, align, flags, ctor); if (s) { diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 3fc69729381..69b70977f00 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -36,7 +36,7 @@ int __init br_fdb_init(void) br_fdb_cache = kmem_cache_create("bridge_fdb_cache", sizeof(struct net_bridge_fdb_entry), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (!br_fdb_cache) return -ENOMEM; diff --git a/net/core/flow.c b/net/core/flow.c index 051430545a0..0ab5234b17d 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -350,7 +350,7 @@ static int __init flow_cache_init(void) flow_cachep = kmem_cache_create("flow_cache", sizeof(struct flow_cache_entry), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL, NULL); + NULL); flow_hash_shift = 10; flow_lwm = 2 * flow_hash_size; flow_hwm = 4 * flow_hash_size; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 9df26a07f06..ca2a1533138 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1347,7 +1347,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) tbl->kmem_cachep = kmem_cache_create(tbl->id, tbl->entry_size, 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL, NULL); + NULL); tbl->stats = alloc_percpu(struct neigh_statistics); if (!tbl->stats) panic("cannot create neighbour cache statistics"); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0583e8498f1..35021eb3ed0 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2021,13 +2021,13 @@ void __init skb_init(void) sizeof(struct sk_buff), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL, NULL); + NULL); skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache", (2*sizeof(struct sk_buff)) + sizeof(atomic_t), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL, NULL); + NULL); } /** diff --git a/net/core/sock.c b/net/core/sock.c index 239a08a6ff2..bd209c4477a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1767,7 +1767,7 @@ int proto_register(struct proto *prot, int alloc_slab) if (alloc_slab) { prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (prot->slab == NULL) { printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n", @@ -1785,7 +1785,7 @@ int proto_register(struct proto *prot, int alloc_slab) sprintf(request_sock_slab_name, mask, prot->name); prot->rsk_prot->slab = kmem_cache_create(request_sock_slab_name, prot->rsk_prot->obj_size, 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (prot->rsk_prot->slab == NULL) { printk(KERN_CRIT "%s: Can't create request sock SLAB cache!\n", @@ -1807,7 +1807,7 @@ int proto_register(struct proto *prot, int alloc_slab) kmem_cache_create(timewait_sock_slab_name, prot->twsk_prot->twsk_obj_size, 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (prot->twsk_prot->twsk_slab == NULL) goto out_free_timewait_sock_slab_name; } diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 01030f34617..7ac775f9a64 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -481,14 +481,14 @@ int __init dccp_ackvec_init(void) { dccp_ackvec_slab = kmem_cache_create("dccp_ackvec", sizeof(struct dccp_ackvec), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (dccp_ackvec_slab == NULL) goto out_err; dccp_ackvec_record_slab = kmem_cache_create("dccp_ackvec_record", sizeof(struct dccp_ackvec_record), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN, NULL); if (dccp_ackvec_record_slab == NULL) goto out_destroy_slab; diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c index d8cf92f09e6..ccbf72c793b 100644 --- a/net/dccp/ccid.c +++ b/net/dccp/ccid.c @@ -69,7 +69,7 @@ static struct kmem_cache *ccid_kmem_cache_create(int obj_size, const char *fmt,. if (slab_name == NULL) return NULL; slab = kmem_cache_create(slab_name, sizeof(struct ccid) + obj_size, 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (slab == NULL) kfree(slab_name); return slab; diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c index dd0fc992b04..174d3f13d93 100644 --- a/net/dccp/ccids/lib/loss_interval.c +++ b/net/dccp/ccids/lib/loss_interval.c @@ -282,7 +282,7 @@ static __init int dccp_li_init(void) { dccp_li_cachep = kmem_cache_create("dccp_li_hist", sizeof(struct dccp_li_hist_entry), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN, NULL); return dccp_li_cachep == NULL ? -ENOBUFS : 0; } diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c index 2e8ef42721e..34c4f604772 100644 --- a/net/dccp/ccids/lib/packet_history.c +++ b/net/dccp/ccids/lib/packet_history.c @@ -59,7 +59,7 @@ struct dccp_tx_hist *dccp_tx_hist_new(const char *name) hist->dccptxh_slab = kmem_cache_create(slab_name, sizeof(struct dccp_tx_hist_entry), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (hist->dccptxh_slab == NULL) goto out_free_slab_name; out: @@ -148,7 +148,7 @@ struct dccp_rx_hist *dccp_rx_hist_new(const char *name) hist->dccprxh_slab = kmem_cache_create(slab_name, sizeof(struct dccp_rx_hist_entry), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (hist->dccprxh_slab == NULL) goto out_free_slab_name; out: diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 6607b7b14f3..04b59ec4f51 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -1003,7 +1003,7 @@ static int __init dccp_init(void) dccp_hashinfo.bind_bucket_cachep = kmem_cache_create("dccp_bind_bucket", sizeof(struct inet_bind_bucket), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (!dccp_hashinfo.bind_bucket_cachep) goto out; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 82622fb6f68..f2a61ef2af9 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1770,7 +1770,7 @@ void __init dn_route_init(void) dn_dst_ops.kmem_cachep = kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); init_timer(&dn_route_timer); dn_route_timer.function = dn_dst_check_expire; dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ; diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index d6615c9361e..fda0772fa21 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -881,7 +881,7 @@ void __init dn_fib_table_init(void) dn_hash_kmem = kmem_cache_create("dn_fib_info_cache", sizeof(struct dn_fib_info), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); } void __exit dn_fib_table_cleanup(void) diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 07e843a47dd..9ad1d9ff9ce 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -771,13 +771,13 @@ struct fib_table * __init fib_hash_init(u32 id) fn_hash_kmem = kmem_cache_create("ip_fib_hash", sizeof(struct fib_node), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (fn_alias_kmem == NULL) fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash), GFP_KERNEL); diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 30e332ade61..9ca786a6fd3 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1970,7 +1970,7 @@ struct fib_table * __init fib_hash_init(u32 id) fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie), GFP_KERNEL); diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 2f44e612806..6cbce96a54c 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -123,7 +123,7 @@ void __init inet_initpeers(void) peer_cachep = kmem_cache_create("inet_peer_cache", sizeof(struct inet_peer), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL, NULL); + NULL); /* All the timers, started at system startup tend to synchronize. Perturb it a bit. diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index d96582acdf6..7003cc1b7fe 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1917,7 +1917,7 @@ void __init ip_mr_init(void) mrt_cachep = kmem_cache_create("ip_mrt_cache", sizeof(struct mfc_cache), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL, NULL); + NULL); init_timer(&ipmr_expire_timer); ipmr_expire_timer.function=ipmr_expire_process; register_netdevice_notifier(&ip_mr_notifier); diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index 3b446b1a6b9..d612a6a5d95 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c @@ -901,7 +901,7 @@ int ip_vs_conn_init(void) /* Allocate ip_vs_conn slab cache */ ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn", sizeof(struct ip_vs_conn), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (!ip_vs_conn_cachep) { vfree(ip_vs_conn_tab); return -ENOMEM; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 88fa648d7ba..df42b7fb326 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2967,7 +2967,7 @@ int __init ip_rt_init(void) ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 987b94403be..da4c0b6ab79 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2430,7 +2430,7 @@ void __init tcp_init(void) tcp_hashinfo.bind_bucket_cachep = kmem_cache_create("tcp_bind_bucket", sizeof(struct inet_bind_bucket), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); /* Size and allocate the main established and bind bucket * hash tables. diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 662a7d9681f..6a612a701ea 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1474,7 +1474,7 @@ void __init fib6_init(void) fib6_node_kmem = kmem_cache_create("fib6_nodes", sizeof(struct fib6_node), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL, NULL); + NULL); fib6_tables_init(); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index fe8d9837f9f..919de682b33 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2555,7 +2555,7 @@ void __init ip6_route_init(void) #endif ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; fib6_init(); diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 6f87dd568de..30f3236c402 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -84,7 +84,7 @@ static int xfrm6_tunnel_spi_init(void) xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", sizeof(struct xfrm6_tunnel_spi), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!xfrm6_tunnel_spi_kmem) return -ENOMEM; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 8cce814f6be..aa086c83af8 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1108,7 +1108,7 @@ int __init nf_conntrack_init(void) nf_conntrack_cachep = kmem_cache_create("nf_conntrack", sizeof(struct nf_conn), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!nf_conntrack_cachep) { printk(KERN_ERR "Unable to create nf_conn slab cache\n"); goto err_free_hash; diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 2191fe008f6..1aa6229ca99 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -540,7 +540,7 @@ int __init nf_conntrack_expect_init(void) nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", sizeof(struct nf_conntrack_expect), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!nf_ct_expect_cachep) goto err2; diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index d6b3d01975b..bd45f9d3f7d 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -738,7 +738,7 @@ static int __init xt_hashlimit_init(void) err = -ENOMEM; hashlimit_cachep = kmem_cache_create("xt_hashlimit", sizeof(struct dsthash_ent), 0, 0, - NULL, NULL); + NULL); if (!hashlimit_cachep) { printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); goto err2; diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 46f6d572ad2..16a68df4e36 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -792,7 +792,7 @@ static int __init af_rxrpc_init(void) ret = -ENOMEM; rxrpc_call_jar = kmem_cache_create( "rxrpc_call_jar", sizeof(struct rxrpc_call), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (!rxrpc_call_jar) { printk(KERN_NOTICE "RxRPC: Failed to allocate call jar\n"); goto error_call_jar; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 34bab36637a..e98579b788b 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -980,14 +980,14 @@ SCTP_STATIC __init int sctp_init(void) sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket", sizeof(struct sctp_bind_bucket), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!sctp_bucket_cachep) goto out; sctp_chunk_cachep = kmem_cache_create("sctp_chunk", sizeof(struct sctp_chunk), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!sctp_chunk_cachep) goto err_chunk_cachep; diff --git a/net/socket.c b/net/socket.c index b7111425004..ec077037f53 100644 --- a/net/socket.c +++ b/net/socket.c @@ -272,8 +272,7 @@ static int init_inodecache(void) (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD), - init_once, - NULL); + init_once); if (sock_inode_cachep == NULL) return -ENOMEM; return 0; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 5b2b6fb244f..650af064ff8 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -867,7 +867,7 @@ int register_rpc_pipefs(void) sizeof(struct rpc_inode), 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (!rpc_inode_cachep) return -ENOMEM; err = register_filesystem(&rpc_pipe_fs_type); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 2ac43c41c3a..b5723c262a3 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -1031,13 +1031,13 @@ rpc_init_mempool(void) rpc_task_slabp = kmem_cache_create("rpc_tasks", sizeof(struct rpc_task), 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!rpc_task_slabp) goto err_nomem; rpc_buffer_slabp = kmem_cache_create("rpc_buffers", RPC_BUFFER_MAXSIZE, 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); + NULL); if (!rpc_buffer_slabp) goto err_nomem; rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE, diff --git a/net/tipc/handler.c b/net/tipc/handler.c index e1dcf663f8a..0c70010a7df 100644 --- a/net/tipc/handler.c +++ b/net/tipc/handler.c @@ -97,7 +97,7 @@ int tipc_handler_start(void) { tipc_queue_item_cache = kmem_cache_create("tipc_queue_items", sizeof(struct queue_item), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN, NULL); if (!tipc_queue_item_cache) return -ENOMEM; diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 5c4695840c5..113f4442998 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -83,5 +83,5 @@ void __init xfrm_input_init(void) secpath_cachep = kmem_cache_create("secpath_cache", sizeof(struct sec_path), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL, NULL); + NULL); } diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index cfaf17c8851..c3a4b0a1868 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2378,7 +2378,7 @@ static void __init xfrm_policy_init(void) xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", sizeof(struct xfrm_dst), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL, NULL); + NULL); hmask = 8 - 1; sz = (hmask+1) * sizeof(struct hlist_head); diff --git a/security/keys/key.c b/security/keys/key.c index 700400d801d..01bbc6d9d19 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -1001,7 +1001,7 @@ void __init key_init(void) { /* allocate a slab in which we can store keys */ key_jar = kmem_cache_create("key_jar", sizeof(struct key), - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); /* add the special key types */ list_add_tail(&key_type_keyring.link, &key_types_list); diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 78c408fd2b0..ecd06738453 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -239,7 +239,7 @@ void __init avc_init(void) atomic_set(&avc_cache.lru_hint, 0); avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), - 0, SLAB_PANIC, NULL, NULL); + 0, SLAB_PANIC, NULL); audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 26356e67108..0fac6829c63 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4913,7 +4913,7 @@ static __init int selinux_init(void) sel_inode_cache = kmem_cache_create("selinux_inode_security", sizeof(struct inode_security_struct), - 0, SLAB_PANIC, NULL, NULL); + 0, SLAB_PANIC, NULL); avc_init(); original_ops = secondary_ops = security_ops; diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 3122908afdc..85705eb289e 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -445,7 +445,7 @@ void avtab_cache_init(void) { avtab_node_cachep = kmem_cache_create("avtab_node", sizeof(struct avtab_node), - 0, SLAB_PANIC, NULL, NULL); + 0, SLAB_PANIC, NULL); } void avtab_cache_destroy(void) -- cgit v1.2.3-70-g09d2 From 41089644c110756a6d09ace77c8d7624660d086a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Jul 2007 10:59:06 +0100 Subject: fix broken handling of port=... in NFS option parsing Obviously broken on little-endian; fortunately, the option is not frequently used... Signed-off-by: Al Viro [ Hey, sparse is wonderful, but even better than sparse is having people like Al that actually _run_ it and fix bugs using it. - Linus ] Signed-off-by: Linus Torvalds --- fs/nfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index b34b7a711d5..b2a851c1b8c 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -732,7 +732,7 @@ static int nfs_parse_mount_options(char *raw, return 0; if (option < 0 || option > 65535) return 0; - mnt->nfs_server.address.sin_port = htonl(option); + mnt->nfs_server.address.sin_port = htons(option); break; case Opt_rsize: if (match_int(args, &mnt->rsize)) -- cgit v1.2.3-70-g09d2