From 6c2689a530cc4a846dc4e36a19812b88b7bfe117 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:04:40 -0700 Subject: NFSv2/v3/v4: Prepare the nfs_page struct to allow for short reads. --- include/linux/nfs_page.h | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/nfs_xdr.h | 8 ++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index c648312afc0c..3f3508eff03f 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -17,10 +17,14 @@ #include #include +#include + /* * Valid flags for a dirty buffer */ #define PG_BUSY 0 +#define PG_NEED_COMMIT 1 +#define PG_NEED_RESCHED 2 struct nfs_page { struct list_head wb_list, /* Defines state of page: */ @@ -31,6 +35,7 @@ struct nfs_page { struct rpc_cred *wb_cred; struct nfs4_state *wb_state; struct page *wb_page; /* page to read in/write out */ + atomic_t wb_complete; /* i/os we're waiting for */ wait_queue_head_t wb_wait; /* wait queue */ unsigned long wb_index; /* Offset >> PAGE_CACHE_SHIFT */ unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */ @@ -42,6 +47,8 @@ struct nfs_page { }; #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) +#define NFS_NEED_COMMIT(req) (test_bit(PG_NEED_COMMIT,&(req)->wb_flags)) +#define NFS_NEED_RESCHED(req) (test_bit(PG_NEED_RESCHED,&(req)->wb_flags)) extern struct nfs_page *nfs_create_request(struct file *, struct inode *, struct page *, @@ -115,6 +122,38 @@ nfs_list_remove_request(struct nfs_page *req) req->wb_list_head = NULL; } +static inline int +nfs_defer_commit(struct nfs_page *req) +{ + if (test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) + return 0; + return 1; +} + +static inline void +nfs_clear_commit(struct nfs_page *req) +{ + smp_mb__before_clear_bit(); + clear_bit(PG_NEED_COMMIT, &req->wb_flags); + smp_mb__after_clear_bit(); +} + +static inline int +nfs_defer_reschedule(struct nfs_page *req) +{ + if (test_and_set_bit(PG_NEED_RESCHED, &req->wb_flags)) + return 0; + return 1; +} + +static inline void +nfs_clear_reschedule(struct nfs_page *req) +{ + smp_mb__before_clear_bit(); + clear_bit(PG_NEED_RESCHED, &req->wb_flags); + smp_mb__after_clear_bit(); +} + static inline struct nfs_page * nfs_list_entry(struct list_head *head) { diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 52d87f29fdc4..f93789122786 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -656,6 +656,8 @@ struct nfs4_compound { #endif /* CONFIG_NFS_V4 */ +struct nfs_page; + struct nfs_read_data { int flags; struct rpc_task task; @@ -664,12 +666,14 @@ struct nfs_read_data { fl_owner_t lockowner; struct nfs_fattr fattr; /* fattr storage */ struct list_head pages; /* Coalesced read requests */ + struct nfs_page *req; /* multi ops per nfs_page */ struct page *pagevec[NFS_READ_MAXIOV]; struct nfs_readargs args; struct nfs_readres res; #ifdef CONFIG_NFS_V4 unsigned long timestamp; /* For lease renewal */ #endif + void (*complete) (struct nfs_read_data *, int); }; struct nfs_write_data { @@ -681,16 +685,16 @@ struct nfs_write_data { struct nfs_fattr fattr; struct nfs_writeverf verf; struct list_head pages; /* Coalesced requests we wish to flush */ + struct nfs_page *req; /* multi ops per nfs_page */ struct page *pagevec[NFS_WRITE_MAXIOV]; struct nfs_writeargs args; /* argument struct */ struct nfs_writeres res; /* result struct */ #ifdef CONFIG_NFS_V4 unsigned long timestamp; /* For lease renewal */ #endif + void (*complete) (struct nfs_write_data *, int); }; -struct nfs_page; - /* * RPC procedure vector for NFSv2/NFSv3 demuxing */ -- cgit v1.2.3 From 7e19d1900fe80a37e2bd5c4138167b5a6fee9d80 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:11:31 -0700 Subject: NFSv2/v3/v4: Add support for asynchronous reads even if rsizefiles, }, .res = { .fattr = &rdata.fattr, diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 5f3443baee69..c75d6373a43c 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -729,11 +729,10 @@ nfs3_read_done(struct rpc_task *task) } static void -nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count) +nfs3_proc_read_setup(struct nfs_read_data *data) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; - struct nfs_page *req; int flags; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_READ], @@ -741,27 +740,13 @@ nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count) .rpc_resp = &data->res, .rpc_cred = data->cred, }; - - req = nfs_list_entry(data->pages.next); - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.pages = data->pagevec; - data->args.count = count; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.eof = 0; - + /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_readdata_release; - - rpc_call_setup(&data->task, &msg, 0); + rpc_call_setup(task, &msg, 0); } static void diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9efe346181bc..689deaa26bb0 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1096,10 +1096,10 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp) if (filp) { struct nfs4_state *state; state = (struct nfs4_state *)filp->private_data; - nfs4_copy_stateid(&rdata->args.stateid, state, rdata->lockowner); + rdata->args.state = state; msg.rpc_cred = state->owner->so_cred; } else { - memcpy(&rdata->args.stateid, &zero_stateid, sizeof(rdata->args.stateid)); + rdata->args.state = NULL; msg.rpc_cred = NFS_I(inode)->mm_cred; } @@ -1509,20 +1509,6 @@ nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); } -static void -nfs4_restart_read(struct rpc_task *task) -{ - struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; - struct nfs_page *req; - - rpc_restart_call(task); - req = nfs_list_entry(data->pages.next); - if (req->wb_state) - nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner); - else - memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid)); -} - static void nfs4_read_done(struct rpc_task *task) { @@ -1530,7 +1516,7 @@ nfs4_read_done(struct rpc_task *task) struct inode *inode = data->inode; if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { - task->tk_action = nfs4_restart_read; + rpc_restart_call(task); return; } if (task->tk_status > 0) @@ -1540,7 +1526,7 @@ nfs4_read_done(struct rpc_task *task) } static void -nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count) +nfs4_proc_read_setup(struct nfs_read_data *data) { struct rpc_task *task = &data->task; struct rpc_message msg = { @@ -1550,34 +1536,15 @@ nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count) .rpc_cred = data->cred, }; struct inode *inode = data->inode; - struct nfs_page *req = nfs_list_entry(data->pages.next); int flags; - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.pages = data->pagevec; - data->args.count = count; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.eof = 0; data->timestamp = jiffies; - data->lockowner = req->wb_lockowner; - if (req->wb_state) - nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner); - else - memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid)); - /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_readdata_release; - rpc_call_setup(task, &msg, 0); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 3cf1a83df495..db5be6d7da51 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -868,14 +868,32 @@ encode_putrootfh(struct xdr_stream *xdr) return 0; } +static void +encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner) +{ + extern nfs4_stateid zero_stateid; + nfs4_stateid stateid; + uint32_t *p; + + RESERVE_SPACE(16); + if (state != NULL) { + nfs4_copy_stateid(&stateid, state, lockowner); + WRITEMEM(stateid.data, sizeof(stateid.data)); + } else + WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data)); +} + static int encode_read(struct xdr_stream *xdr, struct nfs_readargs *args) { uint32_t *p; - RESERVE_SPACE(32); + RESERVE_SPACE(4); WRITE32(OP_READ); - WRITEMEM(args->stateid.data, sizeof(args->stateid.data)); + + encode_stateid(xdr, args->state, args->lockowner); + + RESERVE_SPACE(12); WRITE64(args->offset); WRITE32(args->count); diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index ca4eccd03adf..6756717a7e76 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -559,11 +559,10 @@ nfs_read_done(struct rpc_task *task) } static void -nfs_proc_read_setup(struct nfs_read_data *data, unsigned int count) +nfs_proc_read_setup(struct nfs_read_data *data) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; - struct nfs_page *req; int flags; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_READ], @@ -571,27 +570,13 @@ nfs_proc_read_setup(struct nfs_read_data *data, unsigned int count) .rpc_resp = &data->res, .rpc_cred = data->cred, }; - - req = nfs_list_entry(data->pages.next); - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.pages = data->pagevec; - data->args.count = count; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.eof = 0; - + /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs_read_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_readdata_release; - - rpc_call_setup(&data->task, &msg, 0); + rpc_call_setup(task, &msg, 0); } static void diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 4b929887c5a4..c7b8ae327ad7 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -35,6 +35,8 @@ #define NFSDBG_FACILITY NFSDBG_PAGECACHE static int nfs_pagein_one(struct list_head *, struct inode *); +static void nfs_readpage_result_partial(struct nfs_read_data *, int); +static void nfs_readpage_result_full(struct nfs_read_data *, int); static kmem_cache_t *nfs_rdata_cachep; static mempool_t *nfs_rdata_mempool; @@ -57,12 +59,37 @@ static __inline__ void nfs_readdata_free(struct nfs_read_data *p) mempool_free(p, nfs_rdata_mempool); } -void nfs_readdata_release(struct rpc_task *task) +static void nfs_readdata_release(struct rpc_task *task) { struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; nfs_readdata_free(data); } +static +unsigned int nfs_page_length(struct inode *inode, struct page *page) +{ + loff_t i_size = i_size_read(inode); + unsigned long idx; + + if (i_size <= 0) + return 0; + idx = (i_size - 1) >> PAGE_CACHE_SHIFT; + if (page->index > idx) + return 0; + if (page->index != idx) + return PAGE_CACHE_SIZE; + return 1 + ((i_size - 1) & (PAGE_CACHE_SIZE - 1)); +} + +static +int nfs_return_empty_page(struct page *page) +{ + memclear_highpage_flush(page, 0, PAGE_CACHE_SIZE); + SetPageUptodate(page); + unlock_page(page); + return 0; +} + /* * Read a page synchronously. */ @@ -78,6 +105,7 @@ nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page) .inode = inode, .args = { .fh = NFS_FH(inode), + .lockowner = current->files, .pages = &page, .pgbase = 0UL, .count = rsize, @@ -146,89 +174,208 @@ nfs_readpage_async(struct file *file, struct inode *inode, struct page *page) { LIST_HEAD(one_request); struct nfs_page *new; + unsigned int len; - new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE); + len = nfs_page_length(inode, page); + if (len == 0) + return nfs_return_empty_page(page); + new = nfs_create_request(file, inode, page, 0, len); if (IS_ERR(new)) { unlock_page(page); return PTR_ERR(new); } + if (len < PAGE_CACHE_SIZE) + memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); + nfs_lock_request(new); nfs_list_add_request(new, &one_request); nfs_pagein_one(&one_request, inode); return 0; } +static void nfs_readpage_release(struct nfs_page *req) +{ + unlock_page(req->wb_page); + + nfs_clear_request(req); + nfs_release_request(req); + nfs_unlock_request(req); + + dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", + req->wb_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_inode), + req->wb_bytes, + (long long)req_offset(req)); +} + /* * Set up the NFS read request struct */ -static void -nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data) +static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, + unsigned int count, unsigned int offset) { struct inode *inode; - struct nfs_page *req; - struct page **pages; - unsigned int count; - pages = data->pagevec; - count = 0; - while (!list_empty(head)) { - req = nfs_list_entry(head->next); - nfs_list_remove_request(req); - nfs_list_add_request(req, &data->pages); - *pages++ = req->wb_page; - count += req->wb_bytes; - } - req = nfs_list_entry(data->pages.next); + data->req = req; data->inode = inode = req->wb_inode; data->cred = req->wb_cred; - NFS_PROTO(inode)->read_setup(data, count); + data->args.fh = NFS_FH(inode); + data->args.offset = req_offset(req) + offset; + data->args.pgbase = req->wb_pgbase + offset; + data->args.pages = data->pagevec; + data->args.count = count; + data->args.lockowner = req->wb_lockowner; + data->args.state = req->wb_state; + + data->res.fattr = &data->fattr; + data->res.count = count; + data->res.eof = 0; + + NFS_PROTO(inode)->read_setup(data); - dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu.\n", + data->task.tk_calldata = data; + /* Release requests */ + data->task.tk_release = nfs_readdata_release; + + dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), count, - (unsigned long long)req_offset(req)); + (unsigned long long)data->args.offset); } static void nfs_async_read_error(struct list_head *head) { struct nfs_page *req; - struct page *page; while (!list_empty(head)) { req = nfs_list_entry(head->next); - page = req->wb_page; nfs_list_remove_request(req); - SetPageError(page); - unlock_page(page); - nfs_clear_request(req); - nfs_release_request(req); - nfs_unlock_request(req); + SetPageError(req->wb_page); + nfs_readpage_release(req); } } -static int -nfs_pagein_one(struct list_head *head, struct inode *inode) +/* + * Start an async read operation + */ +static void nfs_execute_read(struct nfs_read_data *data) +{ + struct rpc_clnt *clnt = NFS_CLIENT(data->inode); + sigset_t oldset; + + rpc_clnt_sigmask(clnt, &oldset); + lock_kernel(); + rpc_execute(&data->task); + unlock_kernel(); + rpc_clnt_sigunmask(clnt, &oldset); +} + +/* + * Generate multiple requests to fill a single page. + * + * We optimize to reduce the number of read operations on the wire. If we + * detect that we're reading a page, or an area of a page, that is past the + * end of file, we do not generate NFS read operations but just clear the + * parts of the page that would have come back zero from the server anyway. + * + * We rely on the cached value of i_size to make this determination; another + * client can fill pages on the server past our cached end-of-file, but we + * won't see the new data until our attribute cache is updated. This is more + * or less conventional NFS client behavior. + */ +static int nfs_pagein_multi(struct list_head *head, struct inode *inode) { - struct rpc_clnt *clnt = NFS_CLIENT(inode); + struct nfs_page *req = nfs_list_entry(head->next); + struct page *page = req->wb_page; + struct nfs_read_data *data; + unsigned int rsize = NFS_SERVER(inode)->rsize; + unsigned int nbytes, offset; + int requests = 0; + LIST_HEAD(list); + + nfs_list_remove_request(req); + + nbytes = req->wb_bytes; + for(;;) { + data = nfs_readdata_alloc(); + if (!data) + goto out_bad; + list_add(&data->pages, &list); + requests++; + if (nbytes <= rsize) + break; + nbytes -= rsize; + } + atomic_set(&req->wb_complete, requests); + + ClearPageError(page); + offset = 0; + nbytes = req->wb_bytes; + do { + data = list_entry(list.next, struct nfs_read_data, pages); + list_del_init(&data->pages); + + data->pagevec[0] = page; + data->complete = nfs_readpage_result_partial; + + if (nbytes > rsize) { + nfs_read_rpcsetup(req, data, rsize, offset); + offset += rsize; + nbytes -= rsize; + } else { + nfs_read_rpcsetup(req, data, nbytes, offset); + nbytes = 0; + } + nfs_execute_read(data); + } while (nbytes != 0); + + return 0; + +out_bad: + while (!list_empty(&list)) { + data = list_entry(list.next, struct nfs_read_data, pages); + list_del(&data->pages); + nfs_readdata_free(data); + } + SetPageError(page); + nfs_readpage_release(req); + return -ENOMEM; +} + +static int nfs_pagein_one(struct list_head *head, struct inode *inode) +{ + struct nfs_page *req; + struct page **pages; struct nfs_read_data *data; - sigset_t oldset; + unsigned int count; + + if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) + return nfs_pagein_multi(head, inode); data = nfs_readdata_alloc(); if (!data) goto out_bad; - nfs_read_rpcsetup(head, data); + pages = data->pagevec; + count = 0; + while (!list_empty(head)) { + req = nfs_list_entry(head->next); + nfs_list_remove_request(req); + nfs_list_add_request(req, &data->pages); + ClearPageError(req->wb_page); + *pages++ = req->wb_page; + count += req->wb_bytes; + } + req = nfs_list_entry(data->pages.next); + + data->complete = nfs_readpage_result_full; + nfs_read_rpcsetup(req, data, count, 0); - /* Start the async call */ - rpc_clnt_sigmask(clnt, &oldset); - lock_kernel(); - rpc_execute(&data->task); - unlock_kernel(); - rpc_clnt_sigunmask(clnt, &oldset); + nfs_execute_read(data); return 0; out_bad: nfs_async_read_error(head); @@ -257,56 +404,85 @@ nfs_pagein_list(struct list_head *head, int rpages) return error; } +/* + * Handle a read reply that fills part of a page. + */ +static void nfs_readpage_result_partial(struct nfs_read_data *data, int status) +{ + struct nfs_page *req = data->req; + struct page *page = req->wb_page; + + if (status >= 0) { + unsigned int request = data->args.count; + unsigned int result = data->res.count; + + if (result < request) { + memclear_highpage_flush(page, + data->args.pgbase + result, + request - result); + if (!data->res.eof) + SetPageError(page); + } + } else + SetPageError(page); + + if (atomic_dec_and_test(&req->wb_complete)) { + if (!PageError(page)) + SetPageUptodate(page); + nfs_readpage_release(req); + } +} + /* * This is the callback from RPC telling us whether a reply was * received or some error occurred (timeout or socket shutdown). */ -void -nfs_readpage_result(struct rpc_task *task) +static void nfs_readpage_result_full(struct nfs_read_data *data, int status) { - struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; unsigned int count = data->res.count; - dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", - task->tk_pid, task->tk_status); - - NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME; while (!list_empty(&data->pages)) { struct nfs_page *req = nfs_list_entry(data->pages.next); struct page *page = req->wb_page; nfs_list_remove_request(req); - if (task->tk_status >= 0) { + if (status >= 0) { if (count < PAGE_CACHE_SIZE) { - memclear_highpage_flush(page, + if (count < req->wb_bytes) + memclear_highpage_flush(page, req->wb_pgbase + count, req->wb_bytes - count); - + if (!data->res.eof) + SetPageError(page); count = 0; } else count -= PAGE_CACHE_SIZE; SetPageUptodate(page); } else SetPageError(page); - unlock_page(page); - - dprintk("NFS: read (%s/%Ld %d@%Ld)\n", - req->wb_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_inode), - req->wb_bytes, - (long long)req_offset(req)); - nfs_clear_request(req); - nfs_release_request(req); - nfs_unlock_request(req); + nfs_readpage_release(req); } } +/* + * This is the callback from RPC telling us whether a reply was + * received or some error occurred (timeout or socket shutdown). + */ +void nfs_readpage_result(struct rpc_task *task) +{ + struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; + int status = task->tk_status; + + dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", + task->tk_pid, status); + + NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME; + data->complete(data, status); +} + /* * Read a page over NFS. - * We read the page synchronously in the following cases: - * - The NFS rsize is smaller than PAGE_CACHE_SIZE. We could kludge our way - * around this by creating several consecutive read requests, but - * that's hardly worth it. + * We read the page synchronously in the following case: * - The error flag is set for this page. This happens only when a * previous async read operation failed. */ @@ -329,7 +505,7 @@ nfs_readpage(struct file *file, struct page *page) if (error) goto out_error; - if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) { + if (!IS_SYNC(inode)) { error = nfs_readpage_async(file, inode, page); goto out; } @@ -350,27 +526,26 @@ struct nfs_readdesc { struct file *filp; }; -static int -readpage_sync_filler(void *data, struct page *page) -{ - struct nfs_readdesc *desc = (struct nfs_readdesc *)data; - return nfs_readpage_sync(desc->filp, page->mapping->host, page); -} - static int readpage_async_filler(void *data, struct page *page) { struct nfs_readdesc *desc = (struct nfs_readdesc *)data; struct inode *inode = page->mapping->host; struct nfs_page *new; + unsigned int len; nfs_wb_page(inode, page); - new = nfs_create_request(desc->filp, inode, page, 0, PAGE_CACHE_SIZE); + len = nfs_page_length(inode, page); + if (len == 0) + return nfs_return_empty_page(page); + new = nfs_create_request(desc->filp, inode, page, 0, len); if (IS_ERR(new)) { SetPageError(page); unlock_page(page); return PTR_ERR(new); } + if (len < PAGE_CACHE_SIZE) + memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); nfs_lock_request(new); nfs_list_add_request(new, desc->head); return 0; @@ -385,14 +560,16 @@ nfs_readpages(struct file *filp, struct address_space *mapping, .filp = filp, .head = &head, }; - struct nfs_server *server = NFS_SERVER(mapping->host); - int is_sync = server->rsize < PAGE_CACHE_SIZE; + struct inode *inode = mapping->host; + struct nfs_server *server = NFS_SERVER(inode); int ret; - ret = read_cache_pages(mapping, pages, - is_sync ? readpage_sync_filler : - readpage_async_filler, - &desc); + dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", + inode->i_sb->s_id, + (long long)NFS_FILEID(inode), + nr_pages); + + ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); if (!list_empty(&head)) { int err = nfs_pagein_list(&head, server->rpages); if (!ret) diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 47123702fbd5..92ed40acf4ae 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -397,7 +397,6 @@ extern int nfs_readpages(struct file *, struct address_space *, struct list_head *, unsigned); extern int nfs_pagein_list(struct list_head *, int); extern void nfs_readpage_result(struct rpc_task *); -extern void nfs_readdata_release(struct rpc_task *); /* * linux/fs/mount_clnt.c diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index f93789122786..ba9051dfddfe 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -229,7 +229,8 @@ struct nfs_lockres { struct nfs_readargs { struct nfs_fh * fh; - nfs4_stateid stateid; + fl_owner_t lockowner; + struct nfs4_state * state; __u64 offset; __u32 count; unsigned int pgbase; @@ -663,7 +664,6 @@ struct nfs_read_data { struct rpc_task task; struct inode *inode; struct rpc_cred *cred; - fl_owner_t lockowner; struct nfs_fattr fattr; /* fattr storage */ struct list_head pages; /* Coalesced read requests */ struct nfs_page *req; /* multi ops per nfs_page */ @@ -741,7 +741,7 @@ struct nfs_rpc_ops { int (*pathconf) (struct nfs_server *, struct nfs_fh *, struct nfs_pathconf *); u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); - void (*read_setup) (struct nfs_read_data *, unsigned int count); + void (*read_setup) (struct nfs_read_data *); void (*write_setup) (struct nfs_write_data *, unsigned int count, int how); void (*commit_setup) (struct nfs_write_data *, u64 start, u32 len, int how); int (*file_open) (struct inode *, struct file *); -- cgit v1.2.3 From b13556045f4e662eb578fd801a5c27b1fc31d492 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:13:40 -0700 Subject: NFSv2/v3/v4: Add support for asynchronous writes even if wsizefiles, }, .res = { .fattr = &wdata.fattr, diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index c75d6373a43c..c79c0a9abf20 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -763,11 +763,10 @@ nfs3_write_done(struct rpc_task *task) } static void -nfs3_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) +nfs3_proc_write_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; - struct nfs_page *req; int stable; int flags; struct rpc_message msg = { @@ -784,28 +783,14 @@ nfs3_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) stable = NFS_DATA_SYNC; } else stable = NFS_UNSTABLE; - - req = nfs_list_entry(data->pages.next); - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.count = count; data->args.stable = stable; - data->args.pages = data->pagevec; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.verf = &data->verf; /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs3_write_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_writedata_release; - - rpc_call_setup(&data->task, &msg, 0); + rpc_call_setup(task, &msg, 0); } static void @@ -822,7 +807,7 @@ nfs3_commit_done(struct rpc_task *task) } static void -nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how) +nfs3_proc_commit_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; @@ -834,23 +819,12 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how) .rpc_cred = data->cred, }; - data->args.fh = NFS_FH(data->inode); - data->args.offset = start; - data->args.count = len; - data->res.count = len; - data->res.fattr = &data->fattr; - data->res.verf = &data->verf; - /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_commit_release; - - rpc_call_setup(&data->task, &msg, 0); + rpc_call_setup(task, &msg, 0); } /* diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 689deaa26bb0..149d430aff57 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1134,10 +1134,10 @@ nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp) if (filp) { struct nfs4_state *state; state = (struct nfs4_state *)filp->private_data; - nfs4_copy_stateid(&wdata->args.stateid, state, wdata->lockowner); + wdata->args.state = state; msg.rpc_cred = state->owner->so_cred; } else { - memcpy(&wdata->args.stateid, &zero_stateid, sizeof(wdata->args.stateid)); + wdata->args.state = NULL; msg.rpc_cred = NFS_I(inode)->mm_cred; } @@ -1166,15 +1166,10 @@ nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp) /* * Try first to use O_WRONLY, then O_RDWR stateid. */ - if (filp) { - struct nfs4_state *state; - state = (struct nfs4_state *)filp->private_data; - nfs4_copy_stateid(&cdata->args.stateid, state, cdata->lockowner); - msg.rpc_cred = state->owner->so_cred; - } else { - memcpy(&cdata->args.stateid, &zero_stateid, sizeof(cdata->args.stateid)); + if (filp) + msg.rpc_cred = ((struct nfs4_state *)filp->private_data)->owner->so_cred; + else msg.rpc_cred = NFS_I(inode)->mm_cred; - } fattr->valid = 0; status = rpc_call_sync(server->client, &msg, 0); @@ -1548,20 +1543,6 @@ nfs4_proc_read_setup(struct nfs_read_data *data) rpc_call_setup(task, &msg, 0); } -static void -nfs4_restart_write(struct rpc_task *task) -{ - struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; - struct nfs_page *req; - - rpc_restart_call(task); - req = nfs_list_entry(data->pages.next); - if (req->wb_state) - nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner); - else - memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid)); -} - static void nfs4_write_done(struct rpc_task *task) { @@ -1569,7 +1550,7 @@ nfs4_write_done(struct rpc_task *task) struct inode *inode = data->inode; if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { - task->tk_action = nfs4_restart_write; + rpc_restart_call(task); return; } if (task->tk_status >= 0) @@ -1579,7 +1560,7 @@ nfs4_write_done(struct rpc_task *task) } static void -nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) +nfs4_proc_write_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct rpc_message msg = { @@ -1589,7 +1570,6 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) .rpc_cred = data->cred, }; struct inode *inode = data->inode; - struct nfs_page *req = nfs_list_entry(data->pages.next); int stable; int flags; @@ -1600,33 +1580,15 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) stable = NFS_DATA_SYNC; } else stable = NFS_UNSTABLE; - - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.count = count; data->args.stable = stable; - data->args.pages = data->pagevec; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.verf = &data->verf; - data->timestamp = jiffies; - data->lockowner = req->wb_lockowner; - if (req->wb_state) - nfs4_copy_stateid(&data->args.stateid, req->wb_state, req->wb_lockowner); - else - memcpy(&data->args.stateid, &zero_stateid, sizeof(data->args.stateid)); + data->timestamp = jiffies; /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_writedata_release; - rpc_call_setup(task, &msg, 0); } @@ -1637,7 +1599,7 @@ nfs4_commit_done(struct rpc_task *task) struct inode *inode = data->inode; if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { - task->tk_action = nfs4_restart_write; + rpc_restart_call(task); return; } /* Call back common NFS writeback processing */ @@ -1645,7 +1607,7 @@ nfs4_commit_done(struct rpc_task *task) } static void -nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how) +nfs4_proc_commit_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct rpc_message msg = { @@ -1657,22 +1619,11 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how) struct inode *inode = data->inode; int flags; - data->args.fh = NFS_FH(data->inode); - data->args.offset = start; - data->args.count = len; - data->res.count = len; - data->res.fattr = &data->fattr; - data->res.verf = &data->verf; - /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_commit_release; - rpc_call_setup(task, &msg, 0); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index db5be6d7da51..e370ffe1d13f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1075,9 +1075,12 @@ encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args) { uint32_t *p; - RESERVE_SPACE(36); + RESERVE_SPACE(4); WRITE32(OP_WRITE); - WRITEMEM(args->stateid.data, sizeof(args->stateid.data)); + + encode_stateid(xdr, args->state, args->lockowner); + + RESERVE_SPACE(16); WRITE64(args->offset); WRITE32(args->stable); WRITE32(args->count); diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 6756717a7e76..8dc6a981c586 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -590,11 +590,10 @@ nfs_write_done(struct rpc_task *task) } static void -nfs_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) +nfs_proc_write_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; - struct nfs_page *req; int flags; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_WRITE], @@ -604,32 +603,18 @@ nfs_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) }; /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ - - req = nfs_list_entry(data->pages.next); - data->args.fh = NFS_FH(inode); - data->args.offset = req_offset(req); - data->args.pgbase = req->wb_pgbase; - data->args.count = count; data->args.stable = NFS_FILE_SYNC; - data->args.pages = data->pagevec; - data->res.fattr = &data->fattr; - data->res.count = count; - data->res.verf = &data->verf; /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs_write_done, flags); - task->tk_calldata = data; - /* Release requests */ - task->tk_release = nfs_writedata_release; - - rpc_call_setup(&data->task, &msg, 0); + rpc_call_setup(task, &msg, 0); } static void -nfs_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how) +nfs_proc_commit_setup(struct nfs_write_data *data, int how) { BUG(); } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 83bc0b498a01..cfd6fd870152 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -74,6 +74,8 @@ static struct nfs_page * nfs_update_request(struct file*, struct inode *, struct page *, unsigned int, unsigned int); +static void nfs_writeback_done_partial(struct nfs_write_data *, int); +static void nfs_writeback_done_full(struct nfs_write_data *, int); static kmem_cache_t *nfs_wdata_cachep; static mempool_t *nfs_wdata_mempool; @@ -95,7 +97,7 @@ static __inline__ void nfs_writedata_free(struct nfs_write_data *p) mempool_free(p, nfs_wdata_mempool); } -void nfs_writedata_release(struct rpc_task *task) +static void nfs_writedata_release(struct rpc_task *task) { struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata; nfs_writedata_free(wdata); @@ -117,12 +119,6 @@ static __inline__ void nfs_commit_free(struct nfs_write_data *p) mempool_free(p, nfs_commit_mempool); } -void nfs_commit_release(struct rpc_task *task) -{ - struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata; - nfs_commit_free(wdata); -} - /* Adjust the file length if we're writing beyond the end */ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) { @@ -186,6 +182,7 @@ nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page, .inode = inode, .args = { .fh = NFS_FH(inode), + .lockowner = current->files, .pages = &page, .stable = NFS_FILE_SYNC, .pgbase = offset, @@ -299,8 +296,7 @@ nfs_writepage(struct page *page, struct writeback_control *wbc) goto out; do_it: lock_kernel(); - if (NFS_SERVER(inode)->wsize >= PAGE_CACHE_SIZE && !IS_SYNC(inode) && - inode_referenced) { + if (!IS_SYNC(inode) && inode_referenced) { err = nfs_writepage_async(NULL, inode, page, 0, offset); if (err >= 0) err = 0; @@ -365,7 +361,7 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req) /* * Insert a write request into an inode */ -static inline void +static void nfs_inode_remove_request(struct nfs_page *req) { struct nfs_inode *nfsi; @@ -416,7 +412,7 @@ nfs_find_request(struct inode *inode, unsigned long index) /* * Add a request to the inode's dirty list. */ -static inline void +static void nfs_mark_request_dirty(struct nfs_page *req) { struct inode *inode = req->wb_inode; @@ -444,7 +440,7 @@ nfs_dirty_request(struct nfs_page *req) /* * Add a request to the inode's commit list. */ -static inline void +static void nfs_mark_request_commit(struct nfs_page *req) { struct inode *inode = req->wb_inode; @@ -680,11 +676,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign dentry->d_parent->d_name.name, dentry->d_name.name, count, (long long)(page_offset(page) +offset)); - /* - * If wsize is smaller than page size, update and write - * page synchronously. - */ - if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE || IS_SYNC(inode)) { + if (IS_SYNC(inode)) { status = nfs_writepage_sync(file, inode, page, offset, count); if (status > 0) { if (offset == 0 && status == PAGE_CACHE_SIZE) @@ -747,43 +739,149 @@ done: return status; } +static void nfs_writepage_release(struct nfs_page *req) +{ + end_page_writeback(req->wb_page); + +#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) + if (!PageError(req->wb_page)) { + if (NFS_NEED_RESCHED(req)) { + nfs_mark_request_dirty(req); + goto out; + } else if (NFS_NEED_COMMIT(req)) { + nfs_mark_request_commit(req); + goto out; + } + } + nfs_inode_remove_request(req); + +out: + nfs_clear_commit(req); + nfs_clear_reschedule(req); +#else + nfs_inode_remove_request(req); +#endif + nfs_unlock_request(req); +} + /* * Set up the argument/result storage required for the RPC call. */ -static void -nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how) +static void nfs_write_rpcsetup(struct nfs_page *req, + struct nfs_write_data *data, + unsigned int count, unsigned int offset, + int how) { struct rpc_task *task = &data->task; struct inode *inode; - struct nfs_page *req; - struct page **pages; - unsigned int count; /* Set up the RPC argument and reply structs * NB: take care not to mess about with data->commit et al. */ - pages = data->pagevec; - count = 0; - while (!list_empty(head)) { - req = nfs_list_entry(head->next); - nfs_list_remove_request(req); - nfs_list_add_request(req, &data->pages); - SetPageWriteback(req->wb_page); - *pages++ = req->wb_page; - count += req->wb_bytes; - } - req = nfs_list_entry(data->pages.next); + data->req = req; data->inode = inode = req->wb_inode; data->cred = req->wb_cred; - NFS_PROTO(inode)->write_setup(data, count, how); + data->args.fh = NFS_FH(inode); + data->args.offset = req_offset(req) + offset; + data->args.pgbase = req->wb_pgbase + offset; + data->args.pages = data->pagevec; + data->args.count = count; + data->args.lockowner = req->wb_lockowner; + data->args.state = req->wb_state; + + data->res.fattr = &data->fattr; + data->res.count = count; + data->res.verf = &data->verf; + + NFS_PROTO(inode)->write_setup(data, how); + + data->task.tk_calldata = data; + /* Release requests */ + data->task.tk_release = nfs_writedata_release; dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n", task->tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), count, - (unsigned long long)req_offset(req)); + (unsigned long long)data->args.offset); +} + +static void nfs_execute_write(struct nfs_write_data *data) +{ + struct rpc_clnt *clnt = NFS_CLIENT(data->inode); + sigset_t oldset; + + rpc_clnt_sigmask(clnt, &oldset); + lock_kernel(); + rpc_execute(&data->task); + unlock_kernel(); + rpc_clnt_sigunmask(clnt, &oldset); +} + +/* + * Generate multiple small requests to write out a single + * contiguous dirty area on one page. + */ +static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how) +{ + struct nfs_page *req = nfs_list_entry(head->next); + struct page *page = req->wb_page; + struct nfs_write_data *data; + unsigned int wsize = NFS_SERVER(inode)->wsize; + unsigned int nbytes, offset; + int requests = 0; + LIST_HEAD(list); + + nfs_list_remove_request(req); + + nbytes = req->wb_bytes; + for (;;) { + data = nfs_writedata_alloc(); + if (!data) + goto out_bad; + list_add(&data->pages, &list); + requests++; + if (nbytes <= wsize) + break; + nbytes -= wsize; + } + atomic_set(&req->wb_complete, requests); + + ClearPageError(page); + SetPageWriteback(page); + offset = 0; + nbytes = req->wb_bytes; + do { + data = list_entry(list.next, struct nfs_write_data, pages); + list_del_init(&data->pages); + + data->pagevec[0] = page; + data->complete = nfs_writeback_done_partial; + + if (nbytes > wsize) { + nfs_write_rpcsetup(req, data, wsize, offset, how); + offset += wsize; + nbytes -= wsize; + } else { + nfs_write_rpcsetup(req, data, nbytes, offset, how); + nbytes = 0; + } + nfs_execute_write(data); + } while (nbytes != 0); + + return 0; + +out_bad: + while (!list_empty(&list)) { + data = list_entry(list.next, struct nfs_write_data, pages); + list_del(&data->pages); + nfs_writedata_free(data); + } + nfs_mark_request_dirty(req); + nfs_unlock_request(req); + return -ENOMEM; } /* @@ -794,25 +892,38 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how) * This is the case if nfs_updatepage detects a conflicting request * that has been written but not committed. */ -static int -nfs_flush_one(struct list_head *head, struct inode *inode, int how) +static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) { - struct rpc_clnt *clnt = NFS_CLIENT(inode); + struct nfs_page *req; + struct page **pages; struct nfs_write_data *data; - sigset_t oldset; + unsigned int count; + + if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE) + return nfs_flush_multi(head, inode, how); data = nfs_writedata_alloc(); if (!data) goto out_bad; + pages = data->pagevec; + count = 0; + while (!list_empty(head)) { + req = nfs_list_entry(head->next); + nfs_list_remove_request(req); + nfs_list_add_request(req, &data->pages); + ClearPageError(req->wb_page); + SetPageWriteback(req->wb_page); + *pages++ = req->wb_page; + count += req->wb_bytes; + } + req = nfs_list_entry(data->pages.next); + + data->complete = nfs_writeback_done_full; /* Set up the argument struct */ - nfs_write_rpcsetup(head, data, how); + nfs_write_rpcsetup(req, data, count, 0, how); - rpc_clnt_sigmask(clnt, &oldset); - lock_kernel(); - rpc_execute(&data->task); - unlock_kernel(); - rpc_clnt_sigunmask(clnt, &oldset); + nfs_execute_write(data); return 0; out_bad: while (!list_empty(head)) { @@ -851,18 +962,107 @@ nfs_flush_list(struct list_head *head, int wpages, int how) return error; } +/* + * Handle a write reply that flushed part of a page. + */ +static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) +{ + struct nfs_page *req = data->req; + struct page *page = req->wb_page; + + dprintk("NFS: write (%s/%Ld %d@%Ld)", + req->wb_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_inode), + req->wb_bytes, + (long long)req_offset(req)); + + if (status < 0) { + ClearPageUptodate(page); + SetPageError(page); + if (req->wb_file) + req->wb_file->f_error = status; + dprintk(", error = %d\n", status); + } else { +#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) + if (data->verf.committed < NFS_FILE_SYNC) { + if (!NFS_NEED_COMMIT(req)) { + nfs_defer_commit(req); + memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); + dprintk(" defer commit\n"); + } else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) { + nfs_defer_reschedule(req); + dprintk(" server reboot detected\n"); + } + } else +#endif + dprintk(" OK\n"); + } + + if (atomic_dec_and_test(&req->wb_complete)) + nfs_writepage_release(req); +} + +/* + * Handle a write reply that flushes a whole page. + * + * FIXME: There is an inherent race with invalidate_inode_pages and + * writebacks since the page->count is kept > 1 for as long + * as the page has a write request pending. + */ +static void nfs_writeback_done_full(struct nfs_write_data *data, int status) +{ + struct nfs_page *req; + struct page *page; + + /* Update attributes as result of writeback. */ + while (!list_empty(&data->pages)) { + req = nfs_list_entry(data->pages.next); + nfs_list_remove_request(req); + page = req->wb_page; + + dprintk("NFS: write (%s/%Ld %d@%Ld)", + req->wb_inode->i_sb->s_id, + (long long)NFS_FILEID(req->wb_inode), + req->wb_bytes, + (long long)req_offset(req)); + + if (status < 0) { + ClearPageUptodate(page); + SetPageError(page); + if (req->wb_file) + req->wb_file->f_error = status; + end_page_writeback(page); + nfs_inode_remove_request(req); + dprintk(", error = %d\n", status); + goto next; + } + end_page_writeback(page); + +#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) + if (data->args.stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) { + nfs_inode_remove_request(req); + dprintk(" OK\n"); + goto next; + } + memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); + nfs_mark_request_commit(req); + dprintk(" marked for commit\n"); +#else + nfs_inode_remove_request(req); +#endif + next: + nfs_unlock_request(req); + } +} /* * This function is called when the WRITE call is complete. */ -void -nfs_writeback_done(struct rpc_task *task) +void nfs_writeback_done(struct rpc_task *task) { struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; struct nfs_writeargs *argp = &data->args; struct nfs_writeres *resp = &data->res; - struct nfs_page *req; - struct page *page; dprintk("NFS: %4d nfs_writeback_done (status %d)\n", task->tk_pid, task->tk_status); @@ -904,53 +1104,22 @@ nfs_writeback_done(struct rpc_task *task) /* * Process the nfs_page list */ - while (!list_empty(&data->pages)) { - req = nfs_list_entry(data->pages.next); - nfs_list_remove_request(req); - page = req->wb_page; + data->complete(data, task->tk_status); +} - dprintk("NFS: write (%s/%Ld %d@%Ld)", - req->wb_inode->i_sb->s_id, - (long long)NFS_FILEID(req->wb_inode), - req->wb_bytes, - (long long)req_offset(req)); - - if (task->tk_status < 0) { - ClearPageUptodate(page); - SetPageError(page); - if (req->wb_file) - req->wb_file->f_error = task->tk_status; - end_page_writeback(page); - nfs_inode_remove_request(req); - dprintk(", error = %d\n", task->tk_status); - goto next; - } - end_page_writeback(page); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) - if (argp->stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) { - nfs_inode_remove_request(req); - dprintk(" OK\n"); - goto next; - } - memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); - nfs_mark_request_commit(req); - dprintk(" marked for commit\n"); -#else - nfs_inode_remove_request(req); -#endif - next: - nfs_unlock_request(req); - } +static void nfs_commit_release(struct rpc_task *task) +{ + struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata; + nfs_commit_free(wdata); } - -#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) /* * Set up the argument/result storage required for the RPC call. */ -static void -nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how) +static void nfs_commit_rpcsetup(struct list_head *head, + struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct nfs_page *first, *last; @@ -979,7 +1148,18 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how data->inode = inode; data->cred = first->wb_cred; - NFS_PROTO(inode)->commit_setup(data, start, len, how); + data->args.fh = NFS_FH(data->inode); + data->args.offset = start; + data->args.count = len; + data->res.count = len; + data->res.fattr = &data->fattr; + data->res.verf = &data->verf; + + NFS_PROTO(inode)->commit_setup(data, how); + + data->task.tk_calldata = data; + /* Release requests */ + data->task.tk_release = nfs_commit_release; dprintk("NFS: %4d initiated commit call\n", task->tk_pid); } @@ -990,10 +1170,8 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how int nfs_commit_list(struct list_head *head, int how) { - struct rpc_clnt *clnt; struct nfs_write_data *data; struct nfs_page *req; - sigset_t oldset; data = nfs_commit_alloc(); @@ -1002,13 +1180,8 @@ nfs_commit_list(struct list_head *head, int how) /* Set up the argument struct */ nfs_commit_rpcsetup(head, data, how); - clnt = NFS_CLIENT(data->inode); - rpc_clnt_sigmask(clnt, &oldset); - lock_kernel(); - rpc_execute(&data->task); - unlock_kernel(); - rpc_clnt_sigunmask(clnt, &oldset); + nfs_execute_write(data); return 0; out_bad: while (!list_empty(head)) { diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 92ed40acf4ae..910bc16764c4 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -335,10 +335,8 @@ extern int nfs_writepages(struct address_space *, struct writeback_control *); extern int nfs_flush_incompatible(struct file *file, struct page *page); extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); extern void nfs_writeback_done(struct rpc_task *task); -extern void nfs_writedata_release(struct rpc_task *task); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) -extern void nfs_commit_release(struct rpc_task *task); extern void nfs_commit_done(struct rpc_task *); #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index ba9051dfddfe..5c171dd6d818 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -253,7 +253,8 @@ struct nfs_readres { struct nfs_writeargs { struct nfs_fh * fh; - nfs4_stateid stateid; + fl_owner_t lockowner; + struct nfs4_state * state; __u64 offset; __u32 count; enum nfs3_stable_how stable; @@ -681,7 +682,6 @@ struct nfs_write_data { struct rpc_task task; struct inode *inode; struct rpc_cred *cred; - fl_owner_t lockowner; struct nfs_fattr fattr; struct nfs_writeverf verf; struct list_head pages; /* Coalesced requests we wish to flush */ @@ -742,8 +742,8 @@ struct nfs_rpc_ops { struct nfs_pathconf *); u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); void (*read_setup) (struct nfs_read_data *); - void (*write_setup) (struct nfs_write_data *, unsigned int count, int how); - void (*commit_setup) (struct nfs_write_data *, u64 start, u32 len, int how); + void (*write_setup) (struct nfs_write_data *, int how); + void (*commit_setup) (struct nfs_write_data *, int how); int (*file_open) (struct inode *, struct file *); int (*file_release) (struct inode *, struct file *); void (*request_init)(struct nfs_page *, struct file *); -- cgit v1.2.3 From 3208896d58b138023e805a1094834b8f8c06f6ad Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:15:31 -0700 Subject: RPC,NFS: remove instances of tests for waitqueue_active(). Those can be racy. RPC: remove unnecessary support for sk->sk_sleep on those sockets that are owned by the RPC client. --- include/linux/nfs_page.h | 3 +-- net/sunrpc/sched.c | 9 +++------ net/sunrpc/xprt.c | 12 ++---------- 3 files changed, 6 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 3f3508eff03f..454587123f33 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -100,8 +100,7 @@ nfs_unlock_request(struct nfs_page *req) smp_mb__before_clear_bit(); clear_bit(PG_BUSY, &req->wb_flags); smp_mb__after_clear_bit(); - if (waitqueue_active(&req->wb_wait)) - wake_up_all(&req->wb_wait); + wake_up_all(&req->wb_wait); nfs_release_request(req); } diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 3d3f79aae25f..c562c9e8aab6 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -255,13 +255,11 @@ rpc_make_runnable(struct rpc_task *task) return; } rpc_clear_sleeping(task); - if (waitqueue_active(&rpciod_idle)) - wake_up(&rpciod_idle); + wake_up(&rpciod_idle); } } else { rpc_clear_sleeping(task); - if (waitqueue_active(&task->tk_wait)) - wake_up(&task->tk_wait); + wake_up(&task->tk_wait); } } @@ -287,8 +285,7 @@ void rpciod_wake_up(void) { if(rpciod_pid==0) printk(KERN_ERR "rpciod: wot no daemon?\n"); - if (waitqueue_active(&rpciod_idle)) - wake_up(&rpciod_idle); + wake_up(&rpciod_idle); } /* diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 699ea68c03ee..0858560364ec 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -782,8 +782,6 @@ udp_data_ready(struct sock *sk, int len) dropit: skb_free_datagram(sk, skb); out: - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible(sk->sk_sleep); read_unlock(&sk->sk_callback_lock); } @@ -1043,8 +1041,6 @@ tcp_state_change(struct sock *sk) break; } out: - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible_all(sk->sk_sleep); read_unlock(&sk->sk_callback_lock); } @@ -1084,8 +1080,6 @@ xprt_write_space(struct sock *sk) if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) rpc_wake_up_task(xprt->snd_task); spin_unlock_bh(&xprt->sock_lock); - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible(sk->sk_sleep); out: read_unlock(&sk->sk_callback_lock); } @@ -1626,8 +1620,7 @@ xprt_shutdown(struct rpc_xprt *xprt) rpc_wake_up(&xprt->resend); rpc_wake_up(&xprt->pending); rpc_wake_up(&xprt->backlog); - if (waitqueue_active(&xprt->cong_wait)) - wake_up(&xprt->cong_wait); + wake_up(&xprt->cong_wait); del_timer_sync(&xprt->timer); } @@ -1637,8 +1630,7 @@ xprt_shutdown(struct rpc_xprt *xprt) int xprt_clear_backlog(struct rpc_xprt *xprt) { rpc_wake_up_next(&xprt->backlog); - if (waitqueue_active(&xprt->cong_wait)) - wake_up(&xprt->cong_wait); + wake_up(&xprt->cong_wait); return 1; } -- cgit v1.2.3 From 1fe8529da9bae95b6b81d3d45509747e3c63c9b5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:19:27 -0700 Subject: RPC: add fair queueing to the RPC scheduler. If a wait queue is defined as a "priority queue" then requests are dequeued in blocks of 16 in order to work well with write gathering + readahead on the server. There are 3 levels of priority. The high priority tasks get scheduled 16 times for each time the default level gets scheduled. The lowest level gets scheduled once every 4 times the normal level gets scheduled. Original patch contributed by Shantanu Goel. --- fs/nfs/nfs4state.c | 2 +- fs/nfs/read.c | 1 + fs/nfs/write.c | 50 +++++++--- include/linux/nfs_fs.h | 12 ++- include/linux/sunrpc/sched.h | 66 +++++++++---- net/sunrpc/auth_gss/auth_gss.c | 2 +- net/sunrpc/clnt.c | 2 +- net/sunrpc/sched.c | 204 +++++++++++++++++++++++++++++++++++------ net/sunrpc/xprt.c | 8 +- 9 files changed, 280 insertions(+), 67 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 7d19679f6952..9c3405af1f37 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -105,7 +105,7 @@ nfs4_alloc_client(struct in_addr *addr) INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); INIT_LIST_HEAD(&clp->cl_superblocks); init_waitqueue_head(&clp->cl_waitq); - INIT_RPC_WAITQ(&clp->cl_rpcwaitq, "NFS4 client"); + rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); clp->cl_state = 1 << NFS4CLNT_NEW; } return clp; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index c7b8ae327ad7..b6e5a34ee3b5 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -234,6 +234,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, NFS_PROTO(inode)->read_setup(data); + data->task.tk_cookie = (unsigned long)inode; data->task.tk_calldata = data; /* Release requests */ data->task.tk_release = nfs_readdata_release; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0f90d9ec0b4e..61a836f1813b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -173,15 +173,14 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int * Write a page synchronously. * Offset is the data offset within the page. */ -static int -nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page, - unsigned int offset, unsigned int count) +static int nfs_writepage_sync(struct file *file, struct inode *inode, + struct page *page, unsigned int offset, unsigned int count, + int how) { unsigned int wsize = NFS_SERVER(inode)->wsize; int result, written = 0; - int swapfile = IS_SWAPFILE(inode); struct nfs_write_data wdata = { - .flags = swapfile ? NFS_RPC_SWAPFLAGS : 0, + .flags = how, .cred = NULL, .inode = inode, .args = { @@ -205,7 +204,7 @@ nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page, nfs_begin_data_update(inode); do { - if (count < wsize && !swapfile) + if (count < wsize) wdata.args.count = count; wdata.args.offset = page_offset(page) + wdata.args.pgbase; @@ -260,6 +259,15 @@ static int nfs_writepage_async(struct file *file, struct inode *inode, return status; } +static int wb_priority(struct writeback_control *wbc) +{ + if (wbc->for_reclaim) + return FLUSH_HIGHPRI; + if (wbc->for_kupdate) + return FLUSH_LOWPRI; + return 0; +} + /* * Write an mmapped page to the server. */ @@ -270,6 +278,7 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) unsigned offset = PAGE_CACHE_SIZE; loff_t i_size = i_size_read(inode); int inode_referenced = 0; + int priority = wb_priority(wbc); int err; /* @@ -285,7 +294,7 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) end_index = i_size >> PAGE_CACHE_SHIFT; /* Ensure we've flushed out any previous writes */ - nfs_wb_page(inode,page); + nfs_wb_page_priority(inode, page, priority); /* easy case */ if (page->index < end_index) @@ -307,7 +316,7 @@ do_it: err = WRITEPAGE_ACTIVATE; } } else { - err = nfs_writepage_sync(NULL, inode, page, 0, offset); + err = nfs_writepage_sync(NULL, inode, page, 0, offset, priority); if (err == offset) err = 0; } @@ -338,7 +347,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) return 0; nfs_wait_on_write_congestion(mapping, 0); } - err = nfs_flush_inode(inode, 0, 0, 0); + err = nfs_flush_inode(inode, 0, 0, wb_priority(wbc)); if (err < 0) goto out; wbc->nr_to_write -= err; @@ -347,7 +356,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) if (err < 0) goto out; } - err = nfs_commit_inode(inode, 0, 0, 0); + err = nfs_commit_inode(inode, 0, 0, wb_priority(wbc)); if (err > 0) wbc->nr_to_write -= err; out: @@ -719,8 +728,8 @@ nfs_flush_incompatible(struct file *file, struct page *page) * XXX: Keep an eye on generic_file_read to make sure it doesn't do bad * things with a page scheduled for an RPC call (e.g. invalidate it). */ -int -nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count) +int nfs_updatepage(struct file *file, struct page *page, + unsigned int offset, unsigned int count) { struct dentry *dentry = file->f_dentry; struct inode *inode = page->mapping->host; @@ -732,7 +741,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign count, (long long)(page_offset(page) +offset)); if (IS_SYNC(inode)) { - status = nfs_writepage_sync(file, inode, page, offset, count); + status = nfs_writepage_sync(file, inode, page, offset, count, 0); if (status > 0) { if (offset == 0 && status == PAGE_CACHE_SIZE) SetPageUptodate(page); @@ -819,6 +828,17 @@ out: nfs_unlock_request(req); } +static inline int flush_task_priority(int how) +{ + switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) { + case FLUSH_HIGHPRI: + return RPC_PRIORITY_HIGH; + case FLUSH_LOWPRI: + return RPC_PRIORITY_LOW; + } + return RPC_PRIORITY_NORMAL; +} + /* * Set up the argument/result storage required for the RPC call. */ @@ -851,6 +871,8 @@ static void nfs_write_rpcsetup(struct nfs_page *req, NFS_PROTO(inode)->write_setup(data, how); + data->task.tk_priority = flush_task_priority(how); + data->task.tk_cookie = (unsigned long)inode; data->task.tk_calldata = data; /* Release requests */ data->task.tk_release = nfs_writedata_release; @@ -1212,6 +1234,8 @@ static void nfs_commit_rpcsetup(struct list_head *head, NFS_PROTO(inode)->commit_setup(data, how); + data->task.tk_priority = flush_task_priority(how); + data->task.tk_cookie = (unsigned long)inode; data->task.tk_calldata = data; /* Release requests */ data->task.tk_release = nfs_commit_release; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 910bc16764c4..6e62b4e761fe 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -69,6 +69,8 @@ #define FLUSH_SYNC 1 /* file being synced, or contention */ #define FLUSH_WAIT 2 /* wait for completion */ #define FLUSH_STABLE 4 /* commit to stable storage */ +#define FLUSH_LOWPRI 8 /* low priority background flush */ +#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */ #ifdef __KERNEL__ @@ -374,14 +376,18 @@ nfs_wb_all(struct inode *inode) /* * Write back all requests on one page - we do this before reading it. */ -static inline int -nfs_wb_page(struct inode *inode, struct page* page) +static inline int nfs_wb_page_priority(struct inode *inode, struct page* page, int how) { int error = nfs_sync_inode(inode, page->index, 1, - FLUSH_WAIT | FLUSH_STABLE); + how | FLUSH_WAIT | FLUSH_STABLE); return (error < 0) ? error : 0; } +static inline int nfs_wb_page(struct inode *inode, struct page* page) +{ + return nfs_wb_page_priority(inode, page, 0); +} + /* Hack for future NFS swap support */ #ifndef IS_SWAPFILE # define IS_SWAPFILE(inode) (0) diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 6b8e3eb91513..be2e6ef3b793 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -49,6 +49,8 @@ struct rpc_task { tk_cred_retry, tk_suid_retry; + unsigned long tk_cookie; /* Cookie for batching tasks */ + /* * timeout_fn to be executed by timer bottom half * callback to be executed after waking up @@ -72,7 +74,9 @@ struct rpc_task { unsigned long tk_timeout; /* timeout for rpc_sleep() */ unsigned short tk_flags; /* misc flags */ unsigned char tk_active : 1;/* Task has been activated */ + unsigned char tk_priority : 2;/* Task priority */ unsigned long tk_runstate; /* Task run status */ + struct list_head tk_links; /* links to related tasks */ #ifdef RPC_DEBUG unsigned short tk_pid; /* debugging aid */ #endif @@ -137,29 +141,59 @@ typedef void (*rpc_action)(struct rpc_task *); smp_mb__after_clear_bit(); \ } while(0) +/* + * Task priorities. + * Note: if you change these, you must also change + * the task initialization definitions below. + */ +#define RPC_PRIORITY_LOW 0 +#define RPC_PRIORITY_NORMAL 1 +#define RPC_PRIORITY_HIGH 2 +#define RPC_NR_PRIORITY (RPC_PRIORITY_HIGH+1) + /* * RPC synchronization objects */ struct rpc_wait_queue { - struct list_head tasks; + struct list_head tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */ + unsigned long cookie; /* cookie of last task serviced */ + unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */ + unsigned char priority; /* current priority */ + unsigned char count; /* # task groups remaining serviced so far */ + unsigned char nr; /* # tasks remaining for cookie */ #ifdef RPC_DEBUG - char * name; + const char * name; #endif }; +/* + * This is the # requests to send consecutively + * from a single cookie. The aim is to improve + * performance of NFS operations such as read/write. + */ +#define RPC_BATCH_COUNT 16 + #ifndef RPC_DEBUG -# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var)}) -# define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var.tasks,qname) -# define INIT_RPC_WAITQ(ptr,qname) do { \ - INIT_LIST_HEAD(&(ptr)->tasks); \ - } while(0) +# define RPC_WAITQ_INIT(var,qname) { \ + .tasks = { \ + [0] = LIST_HEAD_INIT(var.tasks[0]), \ + [1] = LIST_HEAD_INIT(var.tasks[1]), \ + [2] = LIST_HEAD_INIT(var.tasks[2]), \ + }, \ + } #else -# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var.tasks), qname}) -# define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname) -# define INIT_RPC_WAITQ(ptr,qname) do { \ - INIT_LIST_HEAD(&(ptr)->tasks); (ptr)->name = qname; \ - } while(0) +# define RPC_WAITQ_INIT(var,qname) { \ + .tasks = { \ + [0] = LIST_HEAD_INIT(var.tasks[0]), \ + [1] = LIST_HEAD_INIT(var.tasks[1]), \ + [2] = LIST_HEAD_INIT(var.tasks[2]), \ + }, \ + .name = qname, \ + } #endif +# define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname) + +#define RPC_IS_PRIORITY(q) ((q)->maxpriority > 0) /* * Function prototypes @@ -175,6 +209,8 @@ void rpc_run_child(struct rpc_task *parent, struct rpc_task *child, rpc_action action); int rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *); void rpc_remove_wait_queue(struct rpc_task *); +void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); +void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, rpc_action action, rpc_action timer); void rpc_add_timer(struct rpc_task *, rpc_action); @@ -194,16 +230,14 @@ void rpc_show_tasks(void); int rpc_init_mempool(void); void rpc_destroy_mempool(void); -static __inline__ void -rpc_exit(struct rpc_task *task, int status) +static inline void rpc_exit(struct rpc_task *task, int status) { task->tk_status = status; task->tk_action = NULL; } #ifdef RPC_DEBUG -static __inline__ char * -rpc_qname(struct rpc_wait_queue *q) +static inline const char * rpc_qname(struct rpc_wait_queue *q) { return ((q && q->name) ? q->name : "unknown"); } diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index ccfd79a71e54..84ec888bdc39 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -365,7 +365,7 @@ retry: gss_msg = gss_new; memset(gss_new, 0, sizeof(*gss_new)); INIT_LIST_HEAD(&gss_new->list); - INIT_RPC_WAITQ(&gss_new->waitq, "RPCSEC_GSS upcall waitq"); + rpc_init_wait_queue(&gss_new->waitq, "RPCSEC_GSS upcall waitq"); atomic_set(&gss_new->count, 2); msg = &gss_new->msg; msg->data = &gss_new->uid; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 43f6e8e27b6a..9b0601699e69 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -144,7 +144,7 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname, clnt->cl_vers = version->number; clnt->cl_prot = xprt->prot; clnt->cl_stats = program->stats; - INIT_RPC_WAITQ(&clnt->cl_pmap_default.pm_bindwait, "bindwait"); + rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait"); if (!clnt->cl_port) clnt->cl_autobind = 1; diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index c562c9e8aab6..26aa503b2976 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -161,6 +161,26 @@ rpc_delete_timer(struct rpc_task *task) dprintk("RPC: %4d deleting timer\n", task->tk_pid); } +/* + * Add new request to a priority queue. + */ +static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct rpc_task *task) +{ + struct list_head *q; + struct rpc_task *t; + + q = &queue->tasks[task->tk_priority]; + if (unlikely(task->tk_priority > queue->maxpriority)) + q = &queue->tasks[queue->maxpriority]; + list_for_each_entry(t, q, tk_list) { + if (t->tk_cookie == task->tk_cookie) { + list_add_tail(&task->tk_list, &t->tk_links); + return; + } + } + list_add_tail(&task->tk_list, q); +} + /* * Add new request to wait queue. * @@ -169,8 +189,7 @@ rpc_delete_timer(struct rpc_task *task) * improve overall performance. * Everyone else gets appended to the queue to ensure proper FIFO behavior. */ -static inline int -__rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) +static int __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) { if (task->tk_rpcwait == queue) return 0; @@ -179,10 +198,12 @@ __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) printk(KERN_WARNING "RPC: doubly enqueued task!\n"); return -EWOULDBLOCK; } - if (RPC_IS_SWAPPER(task)) - list_add(&task->tk_list, &queue->tasks); + if (RPC_IS_PRIORITY(queue)) + __rpc_add_wait_queue_priority(queue, task); + else if (RPC_IS_SWAPPER(task)) + list_add(&task->tk_list, &queue->tasks[0]); else - list_add_tail(&task->tk_list, &queue->tasks); + list_add_tail(&task->tk_list, &queue->tasks[0]); task->tk_rpcwait = queue; dprintk("RPC: %4d added to queue %p \"%s\"\n", @@ -191,8 +212,7 @@ __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) return 0; } -int -rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task) +int rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task) { int result; @@ -202,19 +222,36 @@ rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task) return result; } +/* + * Remove request from a priority queue. + */ +static void __rpc_remove_wait_queue_priority(struct rpc_task *task) +{ + struct rpc_task *t; + + if (!list_empty(&task->tk_links)) { + t = list_entry(task->tk_links.next, struct rpc_task, tk_list); + list_move(&t->tk_list, &task->tk_list); + list_splice_init(&task->tk_links, &t->tk_links); + } + list_del(&task->tk_list); +} + /* * Remove request from queue. * Note: must be called with spin lock held. */ -static inline void -__rpc_remove_wait_queue(struct rpc_task *task) +static void __rpc_remove_wait_queue(struct rpc_task *task) { struct rpc_wait_queue *queue = task->tk_rpcwait; if (!queue) return; - list_del(&task->tk_list); + if (RPC_IS_PRIORITY(queue)) + __rpc_remove_wait_queue_priority(task); + else + list_del(&task->tk_list); task->tk_rpcwait = NULL; dprintk("RPC: %4d removed from queue %p \"%s\"\n", @@ -231,6 +268,48 @@ rpc_remove_wait_queue(struct rpc_task *task) spin_unlock_bh(&rpc_queue_lock); } +static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) +{ + queue->priority = priority; + queue->count = 1 << (priority * 2); +} + +static inline void rpc_set_waitqueue_cookie(struct rpc_wait_queue *queue, unsigned long cookie) +{ + queue->cookie = cookie; + queue->nr = RPC_BATCH_COUNT; +} + +static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue) +{ + rpc_set_waitqueue_priority(queue, queue->maxpriority); + rpc_set_waitqueue_cookie(queue, 0); +} + +static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, int maxprio) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(queue->tasks); i++) + INIT_LIST_HEAD(&queue->tasks[i]); + queue->maxpriority = maxprio; + rpc_reset_waitqueue_priority(queue); +#ifdef RPC_DEBUG + queue->name = qname; +#endif +} + +void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname) +{ + __rpc_init_priority_wait_queue(queue, qname, RPC_PRIORITY_HIGH); +} + +void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) +{ + __rpc_init_priority_wait_queue(queue, qname, 0); +} +EXPORT_SYMBOL(rpc_init_wait_queue); + /* * Make an RPC task runnable. * @@ -402,18 +481,73 @@ rpc_wake_up_task(struct rpc_task *task) spin_unlock_bh(&rpc_queue_lock); } +/* + * Wake up the next task on a priority queue. + */ +static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue) +{ + struct list_head *q; + struct rpc_task *task; + + /* + * Service a batch of tasks from a single cookie. + */ + q = &queue->tasks[queue->priority]; + if (!list_empty(q)) { + task = list_entry(q->next, struct rpc_task, tk_list); + if (queue->cookie == task->tk_cookie) { + if (--queue->nr) + goto out; + list_move_tail(&task->tk_list, q); + } + /* + * Check if we need to switch queues. + */ + if (--queue->count) + goto new_cookie; + } + + /* + * Service the next queue. + */ + do { + if (q == &queue->tasks[0]) + q = &queue->tasks[queue->maxpriority]; + else + q = q - 1; + if (!list_empty(q)) { + task = list_entry(q->next, struct rpc_task, tk_list); + goto new_queue; + } + } while (q != &queue->tasks[queue->priority]); + + rpc_reset_waitqueue_priority(queue); + return NULL; + +new_queue: + rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0])); +new_cookie: + rpc_set_waitqueue_cookie(queue, task->tk_cookie); +out: + __rpc_wake_up_task(task); + return task; +} + /* * Wake up the next task on the wait queue. */ -struct rpc_task * -rpc_wake_up_next(struct rpc_wait_queue *queue) +struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue) { struct rpc_task *task = NULL; dprintk("RPC: wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue)); spin_lock_bh(&rpc_queue_lock); - task_for_first(task, &queue->tasks) - __rpc_wake_up_task(task); + if (RPC_IS_PRIORITY(queue)) + task = __rpc_wake_up_next_priority(queue); + else { + task_for_first(task, &queue->tasks[0]) + __rpc_wake_up_task(task); + } spin_unlock_bh(&rpc_queue_lock); return task; @@ -425,15 +559,22 @@ rpc_wake_up_next(struct rpc_wait_queue *queue) * * Grabs rpc_queue_lock */ -void -rpc_wake_up(struct rpc_wait_queue *queue) +void rpc_wake_up(struct rpc_wait_queue *queue) { struct rpc_task *task; + struct list_head *head; spin_lock_bh(&rpc_queue_lock); - while (!list_empty(&queue->tasks)) - task_for_first(task, &queue->tasks) + head = &queue->tasks[queue->maxpriority]; + for (;;) { + while (!list_empty(head)) { + task = list_entry(head->next, struct rpc_task, tk_list); __rpc_wake_up_task(task); + } + if (head == &queue->tasks[0]) + break; + head--; + } spin_unlock_bh(&rpc_queue_lock); } @@ -444,17 +585,22 @@ rpc_wake_up(struct rpc_wait_queue *queue) * * Grabs rpc_queue_lock */ -void -rpc_wake_up_status(struct rpc_wait_queue *queue, int status) +void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) { + struct list_head *head; struct rpc_task *task; spin_lock_bh(&rpc_queue_lock); - while (!list_empty(&queue->tasks)) { - task_for_first(task, &queue->tasks) { + head = &queue->tasks[queue->maxpriority]; + for (;;) { + while (!list_empty(head)) { + task = list_entry(head->next, struct rpc_task, tk_list); task->tk_status = status; __rpc_wake_up_task(task); } + if (head == &queue->tasks[0]) + break; + head--; } spin_unlock_bh(&rpc_queue_lock); } @@ -642,7 +788,7 @@ __rpc_schedule(void) while (1) { spin_lock_bh(&rpc_queue_lock); - task_for_first(task, &schedq.tasks) { + task_for_first(task, &schedq.tasks[0]) { __rpc_remove_wait_queue(task); spin_unlock_bh(&rpc_queue_lock); @@ -706,9 +852,7 @@ rpc_free(struct rpc_task *task) /* * Creation and deletion of RPC task structures */ -inline void -rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, - rpc_action callback, int flags) +void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action callback, int flags) { memset(task, 0, sizeof(*task)); init_timer(&task->tk_timer); @@ -726,6 +870,10 @@ rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, task->tk_cred_retry = 2; task->tk_suid_retry = 1; + task->tk_priority = RPC_PRIORITY_NORMAL; + task->tk_cookie = (unsigned long)current; + INIT_LIST_HEAD(&task->tk_links); + /* Add to global list of all tasks */ spin_lock(&rpc_sched_lock); list_add(&task->tk_task, &all_tasks); @@ -863,7 +1011,7 @@ rpc_find_parent(struct rpc_task *child) struct list_head *le; parent = (struct rpc_task *) child->tk_calldata; - task_for_each(task, le, &childq.tasks) + task_for_each(task, le, &childq.tasks[0]) if (task == parent) return parent; @@ -943,7 +1091,7 @@ static DECLARE_MUTEX_LOCKED(rpciod_running); static inline int rpciod_task_pending(void) { - return !list_empty(&schedq.tasks); + return !list_empty(&schedq.tasks[0]); } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 0858560364ec..c15af4794892 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1458,10 +1458,10 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) } else xprt_default_timeout(&xprt->timeout, xprt->prot); - INIT_RPC_WAITQ(&xprt->pending, "xprt_pending"); - INIT_RPC_WAITQ(&xprt->sending, "xprt_sending"); - INIT_RPC_WAITQ(&xprt->resend, "xprt_resend"); - INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog"); + rpc_init_wait_queue(&xprt->pending, "xprt_pending"); + rpc_init_wait_queue(&xprt->sending, "xprt_sending"); + rpc_init_wait_queue(&xprt->resend, "xprt_resend"); + rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog"); /* initialize free list */ for (req = &xprt->slot[entries-1]; req >= &xprt->slot[0]; req--) -- cgit v1.2.3 From 1582077363b9ab452317051777874efe22e67d50 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:23:05 -0700 Subject: NFSv2/v3/v4: Fix a slowdown of O_SYNC and O_DIRECT writes that resulted from over-aggressive attribute cache revalidation. --- fs/nfs/direct.c | 7 +------ fs/nfs/inode.c | 23 +++++++++++++++++++++++ fs/nfs/write.c | 4 ++-- include/linux/nfs_fs.h | 1 + 4 files changed, 27 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index b7bf89a1a901..70c8fd128376 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -337,8 +337,7 @@ retry: VERF_SIZE) != 0) goto sync_retry; } - nfs_end_data_update(inode); - NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA; + nfs_end_data_update_defer(inode); return tot_bytes; @@ -397,10 +396,6 @@ nfs_direct_write(struct inode *inode, struct file *file, if (result < size) break; } - /* Zap the page cache if we managed to write */ - if (tot_bytes > 0) - invalidate_remote_inode(inode); - return tot_bytes; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2a3cc1f63c0f..54fa2c0799ca 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1012,6 +1012,8 @@ void nfs_begin_data_update(struct inode *inode) * nfs_end_data_update * @inode - pointer to inode * Declare end of the operations that will update file data + * This will mark the inode as immediately needing revalidation + * of its attribute cache. */ void nfs_end_data_update(struct inode *inode) { @@ -1026,6 +1028,27 @@ void nfs_end_data_update(struct inode *inode) atomic_dec(&nfsi->data_updates); } +/** + * nfs_end_data_update_defer + * @inode - pointer to inode + * Declare end of the operations that will update file data + * This will defer marking the inode as needing revalidation + * unless there are no other pending updates. + */ +void nfs_end_data_update_defer(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + if (atomic_dec_and_test(&nfsi->data_updates)) { + /* Mark the attribute cache for revalidation */ + nfsi->flags |= NFS_INO_INVALID_ATTR; + /* Directories and symlinks: invalidate page cache too */ + if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) + nfsi->flags |= NFS_INO_INVALID_DATA; + nfsi->cache_change_attribute ++; + } +} + /** * nfs_refresh_inode - verify consistency of the inode attribute cache * @inode - pointer to inode diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 71edef018f15..6250a5da857f 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -233,7 +233,7 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode, ClearPageError(page); io_error: - nfs_end_data_update(inode); + nfs_end_data_update_defer(inode); if (wdata.cred) put_rpccred(wdata.cred); @@ -404,7 +404,7 @@ nfs_inode_remove_request(struct nfs_page *req) nfsi->npages--; if (!nfsi->npages) { spin_unlock(&nfs_wreq_lock); - nfs_end_data_update(inode); + nfs_end_data_update_defer(inode); iput(inode); } else spin_unlock(&nfs_wreq_lock); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 6e62b4e761fe..fccbab4d02b5 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -277,6 +277,7 @@ extern void nfs_begin_attr_update(struct inode *); extern void nfs_end_attr_update(struct inode *); extern void nfs_begin_data_update(struct inode *); extern void nfs_end_data_update(struct inode *); +extern void nfs_end_data_update_defer(struct inode *); /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ extern u32 root_nfs_parse_addr(char *name); /*__init*/ -- cgit v1.2.3 From 01d37f031f0cda3caeeafa599c8e7e54b862d93c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:24:37 -0700 Subject: RPCSEC_GSS: Fix RPC padding in two instances of RPCSEC_GSS code. RPC: Clean up XDR encoding of opaque data. --- fs/nfs/nfs4xdr.c | 13 +----------- include/linux/sunrpc/xdr.h | 8 ++++++- net/sunrpc/auth_gss/auth_gss.c | 7 ++---- net/sunrpc/sunrpc_syms.c | 1 - net/sunrpc/xdr.c | 48 ++++++++++++++++++++++++++++++++++++------ 5 files changed, 51 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e370ffe1d13f..742958ee2f9e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -297,7 +297,7 @@ struct compound_hdr { *p++ = htonl((uint32_t)(n)); \ } while (0) #define WRITEMEM(ptr,nbytes) do { \ - p = xdr_writemem(p, ptr, nbytes); \ + p = xdr_encode_opaque_fixed(p, ptr, nbytes); \ } while (0) #define RESERVE_SPACE(nbytes) do { \ @@ -306,17 +306,6 @@ struct compound_hdr { BUG_ON(!p); \ } while (0) -static inline -uint32_t *xdr_writemem(uint32_t *p, const void *ptr, int nbytes) -{ - int tmp = XDR_QUADLEN(nbytes); - if (!tmp) - return p; - p[tmp-1] = 0; - memcpy(p, ptr, nbytes); - return p + tmp; -} - static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 0ccaff2cdee2..deac01c2e96a 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -87,7 +87,8 @@ struct xdr_buf { /* * Miscellaneous XDR helper functions */ -u32 * xdr_encode_array(u32 *p, const void *s, unsigned int len); +u32 * xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int len); +u32 * xdr_encode_opaque(u32 *p, const void *ptr, unsigned int len); u32 * xdr_encode_string(u32 *p, const char *s); u32 * xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen); u32 * xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen); @@ -100,6 +101,11 @@ void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int, void xdr_inline_pages(struct xdr_buf *, unsigned int, struct page **, unsigned int, unsigned int); +static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len) +{ + return xdr_encode_opaque(p, s, len); +} + /* * Decode 64bit quantities (NFSv3 support) */ diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 84ec888bdc39..b1b922f09257 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -721,8 +721,7 @@ gss_marshal(struct rpc_task *task, u32 *p, int ruid) printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); goto out_put_ctx; } - *p++ = htonl(mic.len); - p += XDR_QUADLEN(mic.len); + p = xdr_encode_opaque(p, NULL, mic.len); gss_put_ctx(ctx); return p; out_put_ctx: @@ -857,9 +856,7 @@ gss_wrap_req(struct rpc_task *task, status = -EIO; /* XXX? */ if (maj_stat) goto out; - q = p; - *q++ = htonl(mic.len); - q += XDR_QUADLEN(mic.len); + q = xdr_encode_opaque(p, NULL, mic.len); offset = (u8 *)q - (u8 *)p; iov->iov_len += offset; diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 9061f6498cc4..104bd5679272 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -120,7 +120,6 @@ EXPORT_SYMBOL(svcauth_unix_purge); EXPORT_SYMBOL(unix_domain_find); /* Generic XDR */ -EXPORT_SYMBOL(xdr_encode_array); EXPORT_SYMBOL(xdr_encode_string); EXPORT_SYMBOL(xdr_decode_string); EXPORT_SYMBOL(xdr_decode_string_inplace); diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index accfdd9284df..a0b977cfbfc5 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -53,16 +53,50 @@ xdr_decode_netobj(u32 *p, struct xdr_netobj *obj) return p + XDR_QUADLEN(len); } -u32 * -xdr_encode_array(u32 *p, const void *array, unsigned int len) +/** + * xdr_encode_opaque_fixed - Encode fixed length opaque data + * @p - pointer to current position in XDR buffer. + * @ptr - pointer to data to encode (or NULL) + * @nbytes - size of data. + * + * Copy the array of data of length nbytes at ptr to the XDR buffer + * at position p, then align to the next 32-bit boundary by padding + * with zero bytes (see RFC1832). + * Note: if ptr is NULL, only the padding is performed. + * + * Returns the updated current XDR buffer position + * + */ +u32 *xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int nbytes) { - int quadlen = XDR_QUADLEN(len); + if (likely(nbytes != 0)) { + unsigned int quadlen = XDR_QUADLEN(nbytes); + unsigned int padding = (quadlen << 2) - nbytes; + + if (ptr != NULL) + memcpy(p, ptr, nbytes); + if (padding != 0) + memset((char *)p + nbytes, 0, padding); + p += quadlen; + } + return p; +} +EXPORT_SYMBOL(xdr_encode_opaque_fixed); - p[quadlen] = 0; - *p++ = htonl(len); - memcpy(p, array, len); - return p + quadlen; +/** + * xdr_encode_opaque - Encode variable length opaque data + * @p - pointer to current position in XDR buffer. + * @ptr - pointer to data to encode (or NULL) + * @nbytes - size of data. + * + * Returns the updated current XDR buffer position + */ +u32 *xdr_encode_opaque(u32 *p, const void *ptr, unsigned int nbytes) +{ + *p++ = htonl(nbytes); + return xdr_encode_opaque_fixed(p, ptr, nbytes); } +EXPORT_SYMBOL(xdr_encode_opaque); u32 * xdr_encode_string(u32 *p, const char *string) -- cgit v1.2.3 From 677da9bf8a3ac83a1d2f9f2df21b1549583b416e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:25:10 -0700 Subject: NFSv4: attribute bitmap values need to be unsigned long integers. --- include/linux/nfs4.h | 110 +++++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index e8ea2239a213..644cd1c27c47 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -217,63 +217,63 @@ enum lock_type4 { /* Mandatory Attributes */ -#define FATTR4_WORD0_SUPPORTED_ATTRS (1) -#define FATTR4_WORD0_TYPE (1 << 1) -#define FATTR4_WORD0_FH_EXPIRE_TYPE (1 << 2) -#define FATTR4_WORD0_CHANGE (1 << 3) -#define FATTR4_WORD0_SIZE (1 << 4) -#define FATTR4_WORD0_LINK_SUPPORT (1 << 5) -#define FATTR4_WORD0_SYMLINK_SUPPORT (1 << 6) -#define FATTR4_WORD0_NAMED_ATTR (1 << 7) -#define FATTR4_WORD0_FSID (1 << 8) -#define FATTR4_WORD0_UNIQUE_HANDLES (1 << 9) -#define FATTR4_WORD0_LEASE_TIME (1 << 10) -#define FATTR4_WORD0_RDATTR_ERROR (1 << 11) +#define FATTR4_WORD0_SUPPORTED_ATTRS (1UL << 0) +#define FATTR4_WORD0_TYPE (1UL << 1) +#define FATTR4_WORD0_FH_EXPIRE_TYPE (1UL << 2) +#define FATTR4_WORD0_CHANGE (1UL << 3) +#define FATTR4_WORD0_SIZE (1UL << 4) +#define FATTR4_WORD0_LINK_SUPPORT (1UL << 5) +#define FATTR4_WORD0_SYMLINK_SUPPORT (1UL << 6) +#define FATTR4_WORD0_NAMED_ATTR (1UL << 7) +#define FATTR4_WORD0_FSID (1UL << 8) +#define FATTR4_WORD0_UNIQUE_HANDLES (1UL << 9) +#define FATTR4_WORD0_LEASE_TIME (1UL << 10) +#define FATTR4_WORD0_RDATTR_ERROR (1UL << 11) /* Recommended Attributes */ -#define FATTR4_WORD0_ACL (1 << 12) -#define FATTR4_WORD0_ACLSUPPORT (1 << 13) -#define FATTR4_WORD0_ARCHIVE (1 << 14) -#define FATTR4_WORD0_CANSETTIME (1 << 15) -#define FATTR4_WORD0_CASE_INSENSITIVE (1 << 16) -#define FATTR4_WORD0_CASE_PRESERVING (1 << 17) -#define FATTR4_WORD0_CHOWN_RESTRICTED (1 << 18) -#define FATTR4_WORD0_FILEHANDLE (1 << 19) -#define FATTR4_WORD0_FILEID (1 << 20) -#define FATTR4_WORD0_FILES_AVAIL (1 << 21) -#define FATTR4_WORD0_FILES_FREE (1 << 22) -#define FATTR4_WORD0_FILES_TOTAL (1 << 23) -#define FATTR4_WORD0_FS_LOCATIONS (1 << 24) -#define FATTR4_WORD0_HIDDEN (1 << 25) -#define FATTR4_WORD0_HOMOGENEOUS (1 << 26) -#define FATTR4_WORD0_MAXFILESIZE (1 << 27) -#define FATTR4_WORD0_MAXLINK (1 << 28) -#define FATTR4_WORD0_MAXNAME (1 << 29) -#define FATTR4_WORD0_MAXREAD (1 << 30) -#define FATTR4_WORD0_MAXWRITE (1 << 31) -#define FATTR4_WORD1_MIMETYPE (1) -#define FATTR4_WORD1_MODE (1 << 1) -#define FATTR4_WORD1_NO_TRUNC (1 << 2) -#define FATTR4_WORD1_NUMLINKS (1 << 3) -#define FATTR4_WORD1_OWNER (1 << 4) -#define FATTR4_WORD1_OWNER_GROUP (1 << 5) -#define FATTR4_WORD1_QUOTA_HARD (1 << 6) -#define FATTR4_WORD1_QUOTA_SOFT (1 << 7) -#define FATTR4_WORD1_QUOTA_USED (1 << 8) -#define FATTR4_WORD1_RAWDEV (1 << 9) -#define FATTR4_WORD1_SPACE_AVAIL (1 << 10) -#define FATTR4_WORD1_SPACE_FREE (1 << 11) -#define FATTR4_WORD1_SPACE_TOTAL (1 << 12) -#define FATTR4_WORD1_SPACE_USED (1 << 13) -#define FATTR4_WORD1_SYSTEM (1 << 14) -#define FATTR4_WORD1_TIME_ACCESS (1 << 15) -#define FATTR4_WORD1_TIME_ACCESS_SET (1 << 16) -#define FATTR4_WORD1_TIME_BACKUP (1 << 17) -#define FATTR4_WORD1_TIME_CREATE (1 << 18) -#define FATTR4_WORD1_TIME_DELTA (1 << 19) -#define FATTR4_WORD1_TIME_METADATA (1 << 20) -#define FATTR4_WORD1_TIME_MODIFY (1 << 21) -#define FATTR4_WORD1_TIME_MODIFY_SET (1 << 22) +#define FATTR4_WORD0_ACL (1UL << 12) +#define FATTR4_WORD0_ACLSUPPORT (1UL << 13) +#define FATTR4_WORD0_ARCHIVE (1UL << 14) +#define FATTR4_WORD0_CANSETTIME (1UL << 15) +#define FATTR4_WORD0_CASE_INSENSITIVE (1UL << 16) +#define FATTR4_WORD0_CASE_PRESERVING (1UL << 17) +#define FATTR4_WORD0_CHOWN_RESTRICTED (1UL << 18) +#define FATTR4_WORD0_FILEHANDLE (1UL << 19) +#define FATTR4_WORD0_FILEID (1UL << 20) +#define FATTR4_WORD0_FILES_AVAIL (1UL << 21) +#define FATTR4_WORD0_FILES_FREE (1UL << 22) +#define FATTR4_WORD0_FILES_TOTAL (1UL << 23) +#define FATTR4_WORD0_FS_LOCATIONS (1UL << 24) +#define FATTR4_WORD0_HIDDEN (1UL << 25) +#define FATTR4_WORD0_HOMOGENEOUS (1UL << 26) +#define FATTR4_WORD0_MAXFILESIZE (1UL << 27) +#define FATTR4_WORD0_MAXLINK (1UL << 28) +#define FATTR4_WORD0_MAXNAME (1UL << 29) +#define FATTR4_WORD0_MAXREAD (1UL << 30) +#define FATTR4_WORD0_MAXWRITE (1UL << 31) +#define FATTR4_WORD1_MIMETYPE (1UL << 0) +#define FATTR4_WORD1_MODE (1UL << 1) +#define FATTR4_WORD1_NO_TRUNC (1UL << 2) +#define FATTR4_WORD1_NUMLINKS (1UL << 3) +#define FATTR4_WORD1_OWNER (1UL << 4) +#define FATTR4_WORD1_OWNER_GROUP (1UL << 5) +#define FATTR4_WORD1_QUOTA_HARD (1UL << 6) +#define FATTR4_WORD1_QUOTA_SOFT (1UL << 7) +#define FATTR4_WORD1_QUOTA_USED (1UL << 8) +#define FATTR4_WORD1_RAWDEV (1UL << 9) +#define FATTR4_WORD1_SPACE_AVAIL (1UL << 10) +#define FATTR4_WORD1_SPACE_FREE (1UL << 11) +#define FATTR4_WORD1_SPACE_TOTAL (1UL << 12) +#define FATTR4_WORD1_SPACE_USED (1UL << 13) +#define FATTR4_WORD1_SYSTEM (1UL << 14) +#define FATTR4_WORD1_TIME_ACCESS (1UL << 15) +#define FATTR4_WORD1_TIME_ACCESS_SET (1UL << 16) +#define FATTR4_WORD1_TIME_BACKUP (1UL << 17) +#define FATTR4_WORD1_TIME_CREATE (1UL << 18) +#define FATTR4_WORD1_TIME_DELTA (1UL << 19) +#define FATTR4_WORD1_TIME_METADATA (1UL << 20) +#define FATTR4_WORD1_TIME_MODIFY (1UL << 21) +#define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22) #define NFSPROC4_NULL 0 #define NFSPROC4_COMPOUND 1 -- cgit v1.2.3 From 9c0c8d90a1aa0225fd2dc45e6f1e1d25ee71fb25 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:25:55 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating ACCESS RPC calls. --- fs/nfs/nfs4proc.c | 56 +++++++++++++------------------------ fs/nfs/nfs4xdr.c | 74 ++++++++++++++++++++++++++++++++++--------------- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 13 +++++---- 4 files changed, 80 insertions(+), 64 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 149d430aff57..6203634f598a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -81,19 +81,6 @@ nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops, cp->server = server; } -static void -nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported, u32 *resp_access) -{ - struct nfs4_access *access = GET_OP(cp, access); - - access->ac_req_access = req_access; - access->ac_resp_supported = resp_supported; - access->ac_resp_access = resp_access; - - OPNUM(cp) = OP_ACCESS; - cp->req_nops++; -} - static void nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name, struct iattr *sattr, struct nfs4_change_info *info) @@ -989,48 +976,43 @@ nfs4_proc_lookup(struct inode *dir, struct qstr *name, return nfs4_map_errors(status); } -static int -nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode) +static int nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode) { - struct nfs4_compound compound; - struct nfs4_op ops[3]; - struct nfs_fattr fattr; - u32 req_access = 0, resp_supported, resp_access; int status; - - fattr.valid = 0; + struct nfs4_accessargs args = { + .fh = NFS_FH(inode), + }; + struct nfs4_accessres res = { 0 }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], + .rpc_argp = &args, + .rpc_resp = &res, + .rpc_cred = cred, + }; /* * Determine which access bits we want to ask for... */ if (mode & MAY_READ) - req_access |= NFS4_ACCESS_READ; + args.access |= NFS4_ACCESS_READ; if (S_ISDIR(inode->i_mode)) { if (mode & MAY_WRITE) - req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE; + args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE; if (mode & MAY_EXEC) - req_access |= NFS4_ACCESS_LOOKUP; + args.access |= NFS4_ACCESS_LOOKUP; } else { if (mode & MAY_WRITE) - req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND; + args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND; if (mode & MAY_EXEC) - req_access |= NFS4_ACCESS_EXECUTE; + args.access |= NFS4_ACCESS_EXECUTE; } - - nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "access"); - nfs4_setup_putfh(&compound, NFS_FH(inode)); - nfs4_setup_getattr(&compound, &fattr); - nfs4_setup_access(&compound, req_access, &resp_supported, &resp_access); - status = nfs4_call_compound(&compound, cred, 0); - nfs_refresh_inode(inode, &fattr); - + status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (!status) { - if (req_access != resp_supported) { + if (args.access != res.supported) { printk(KERN_NOTICE "NFS: server didn't support all access bits!\n"); status = -ENOTSUPP; - } - else if (req_access != resp_access) + } else if ((args.access & res.access) != args.access) status = -EACCES; } return nfs4_map_errors(status); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 742958ee2f9e..b28f70e3f264 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -255,7 +255,13 @@ static int nfs_stat_to_errno(int); decode_putfh_maxsz + \ decode_getattr_maxsz + \ op_decode_hdr_maxsz + 4) - +#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz + 1) +#define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 2) + static struct { @@ -450,14 +456,13 @@ encode_attrs(struct xdr_stream *xdr, struct iattr *iap, return status; } -static int -encode_access(struct xdr_stream *xdr, struct nfs4_access *access) +static int encode_access(struct xdr_stream *xdr, u32 access) { uint32_t *p; RESERVE_SPACE(8); WRITE32(OP_ACCESS); - WRITE32(access->ac_req_access); + WRITE32(access); return 0; } @@ -832,8 +837,7 @@ encode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeargs *arg) return 0; } -static int -encode_putfh(struct xdr_stream *xdr, struct nfs_fh *fh) +static int encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh) { int len = fh->size; uint32_t *p; @@ -1094,9 +1098,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs for (i = 0; i < cp->req_nops; i++) { switch (cp->ops[i].opnum) { - case OP_ACCESS: - status = encode_access(xdr, &cp->ops[i].u.access); - break; case OP_CREATE: status = encode_create(xdr, &cp->ops[i].u.create, cp->server); break; @@ -1149,7 +1150,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs * END OF "GENERIC" ENCODE ROUTINES. */ - /* * Encode COMPOUND argument */ @@ -1164,6 +1164,26 @@ nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *c cp->timestamp = jiffies; return status; } + +/* + * Encode an ACCESS request + */ +static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putfh(&xdr, args->fh)) == 0) + status = encode_access(&xdr, args->access); + return status; +} + + /* * Encode a CLOSE request */ @@ -1645,8 +1665,7 @@ decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) return 0; } -static int -decode_access(struct xdr_stream *xdr, struct nfs4_access *access) +static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) { uint32_t *p; uint32_t supp, acc; @@ -1658,12 +1677,8 @@ decode_access(struct xdr_stream *xdr, struct nfs4_access *access) READ_BUF(8); READ32(supp); READ32(acc); - if ((supp & ~access->ac_req_access) || (acc & ~supp)) { - printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n"); - return -EIO; - } - *access->ac_resp_supported = supp; - *access->ac_resp_access = acc; + access->supported = supp; + access->access = acc; return 0; } @@ -2077,7 +2092,6 @@ out_bad_bitmap: return -EIO; } - static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) { @@ -2628,9 +2642,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs op = &cp->ops[0]; for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++, op++) { switch (op->opnum) { - case OP_ACCESS: - status = decode_access(xdr, &op->u.access); - break; case OP_CREATE: status = decode_create(xdr, &op->u.create); break; @@ -2728,6 +2739,24 @@ out: return status; } +/* + * Decode ACCESS response + */ +static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) + goto out; + if ((status = decode_putfh(&xdr)) == 0) + status = decode_access(&xdr, res); +out: + return status; +} + /* * Decode CLOSE response */ @@ -3236,6 +3265,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(LOCK, enc_lock, dec_lock), PROC(LOCKT, enc_lockt, dec_lockt), PROC(LOCKU, enc_locku, dec_locku), + PROC(ACCESS, enc_access, dec_access), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 644cd1c27c47..5165192d15e7 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -303,6 +303,7 @@ enum { NFSPROC4_CLNT_LOCK, NFSPROC4_CLNT_LOCKT, NFSPROC4_CLNT_LOCKU, + NFSPROC4_CLNT_ACCESS, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 5c171dd6d818..94ac6db11699 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -484,10 +484,14 @@ struct nfs4_change_info { u64 after; }; -struct nfs4_access { - u32 ac_req_access; /* request */ - u32 * ac_resp_supported; /* response */ - u32 * ac_resp_access; /* response */ +struct nfs4_accessargs { + const struct nfs_fh * fh; + u32 access; +}; + +struct nfs4_accessres { + u32 supported; + u32 access; }; struct nfs4_close { @@ -611,7 +615,6 @@ struct nfs4_setclientid { struct nfs4_op { u32 opnum; union { - struct nfs4_access access; struct nfs4_close close; struct nfs4_create create; struct nfs4_getattr getattr; -- cgit v1.2.3 From 85ac427f21bbb9d73722f9c287b478843198776d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:26:43 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating GETATTR RPC calls. --- fs/nfs/nfs4proc.c | 25 ++- fs/nfs/nfs4xdr.c | 438 +++++++++++++++++++++++++++++++++++++++++++++++- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 20 ++- 4 files changed, 469 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6203634f598a..d3675dbbcdaf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -876,18 +876,25 @@ out: return nfs4_proc_fsinfo(server, fhandle, info); } -static int -nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) +static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) { - struct nfs4_compound compound; - struct nfs4_op ops[2]; - + struct nfs4_getattr_arg args = { + .fh = NFS_FH(inode), + .bitmask = nfs4_fattr_bitmap, + }; + struct nfs4_getattr_res res = { + .fattr = fattr, + .server = NFS_SERVER(inode), + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], + .rpc_argp = &args, + .rpc_resp = &res, + }; + fattr->valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr"); - nfs4_setup_putfh(&compound, NFS_FH(inode)); - nfs4_setup_getattr(&compound, fattr); - return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); + return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0)); } /* diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index b28f70e3f264..8b3c0d43bbd5 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -261,7 +261,13 @@ static int nfs_stat_to_errno(int); #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ op_decode_hdr_maxsz + 2) - +#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_getattr_maxsz) + static struct { @@ -552,6 +558,15 @@ encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1) return 0; } +static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) +{ + extern u32 nfs4_fattr_bitmap[]; + + return encode_getattr_two(xdr, + bitmask[0] & nfs4_fattr_bitmap[0], + bitmask[1] & nfs4_fattr_bitmap[1]); +} + static inline int encode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr) { @@ -837,7 +852,8 @@ encode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeargs *arg) return 0; } -static int encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh) +static int +encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh) { int len = fh->size; uint32_t *p; @@ -1183,6 +1199,23 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct n return status; } +/* + * Encode GETATTR request + */ +static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putfh(&xdr, args->fh)) == 0) + status = encode_getfattr(&xdr, args->bitmask); + return status; +} /* * Encode a CLOSE request @@ -1653,6 +1686,320 @@ decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) return 0; } +static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) +{ + uint32_t bmlen, *p; + + READ_BUF(4); + READ32(bmlen); + + bitmap[0] = bitmap[1] = 0; + READ_BUF((bmlen << 2)); + if (bmlen > 0) { + READ32(bitmap[0]); + if (bmlen > 1) + READ32(bitmap[1]); + } + return 0; +} + +static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, uint32_t **savep) +{ + uint32_t *p; + + READ_BUF(4); + READ32(*attrlen); + *savep = xdr->p; + return 0; +} + +static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type) +{ + uint32_t *p; + + *type = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) { + READ_BUF(4); + READ32(*type); + if (*type < NF4REG || *type > NF4NAMEDATTR) { + dprintk("%s: bad type %d\n", __FUNCTION__, *type); + return -EIO; + } + bitmap[0] &= ~FATTR4_WORD0_TYPE; + } + dprintk("%s: type=0%o\n", __FUNCTION__, nfs_type2fmt[*type].nfs2type); + return 0; +} + +static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change) +{ + uint32_t *p; + + *change = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) { + READ_BUF(8); + READ64(*change); + bitmap[0] &= ~FATTR4_WORD0_CHANGE; + } + dprintk("%s: change attribute=%Lu\n", __FUNCTION__, + (unsigned long long)*change); + return 0; +} + +static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size) +{ + uint32_t *p; + + *size = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) { + READ_BUF(8); + READ64(*size); + bitmap[0] &= ~FATTR4_WORD0_SIZE; + } + dprintk("%s: file size=%Lu\n", __FUNCTION__, (unsigned long long)*size); + return 0; +} + +static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid) +{ + uint32_t *p; + + fsid->major = 0; + fsid->minor = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FSID)) { + READ_BUF(16); + READ64(fsid->major); + READ64(fsid->minor); + bitmap[0] &= ~FATTR4_WORD0_FSID; + } + dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __FUNCTION__, + (unsigned long long)fsid->major, + (unsigned long long)fsid->minor); + return 0; +} + +static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) +{ + uint32_t *p; + + *fileid = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) { + READ_BUF(8); + READ64(*fileid); + bitmap[0] &= ~FATTR4_WORD0_FILEID; + } + dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid); + return 0; +} + +static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode) +{ + uint32_t *p; + + *mode = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_MODE)) { + READ_BUF(4); + READ32(*mode); + *mode &= ~S_IFMT; + bitmap[1] &= ~FATTR4_WORD1_MODE; + } + dprintk("%s: file mode=0%o\n", __FUNCTION__, (unsigned int)*mode); + return 0; +} + +static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink) +{ + uint32_t *p; + + *nlink = 1; + if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) { + READ_BUF(4); + READ32(*nlink); + bitmap[1] &= ~FATTR4_WORD1_NUMLINKS; + } + dprintk("%s: nlink=%u\n", __FUNCTION__, (unsigned int)*nlink); + return 0; +} + +static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid) +{ + uint32_t len, *p; + + *uid = -2; + if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) { + READ_BUF(4); + READ32(len); + READ_BUF(len); + if (len < XDR_MAX_NETOBJ) { + if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0) + dprintk("%s: nfs_map_name_to_uid failed!\n", + __FUNCTION__); + } else + printk(KERN_WARNING "%s: name too long (%u)!\n", + __FUNCTION__, len); + bitmap[1] &= ~FATTR4_WORD1_OWNER; + } + dprintk("%s: uid=%d\n", __FUNCTION__, (int)*uid); + return 0; +} + +static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid) +{ + uint32_t len, *p; + + *gid = -2; + if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) { + READ_BUF(4); + READ32(len); + READ_BUF(len); + if (len < XDR_MAX_NETOBJ) { + if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0) + dprintk("%s: nfs_map_group_to_gid failed!\n", + __FUNCTION__); + } else + printk(KERN_WARNING "%s: name too long (%u)!\n", + __FUNCTION__, len); + bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP; + } + dprintk("%s: gid=%d\n", __FUNCTION__, (int)*gid); + return 0; +} + +static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev) +{ + uint32_t major = 0, minor = 0, *p; + + *rdev = MKDEV(0,0); + if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) { + dev_t tmp; + + READ_BUF(8); + READ32(major); + READ32(minor); + tmp = MKDEV(major, minor); + if (MAJOR(tmp) == major && MINOR(tmp) == minor) + *rdev = tmp; + bitmap[1] &= ~ FATTR4_WORD1_RAWDEV; + } + dprintk("%s: rdev=(0x%x:0x%x)\n", __FUNCTION__, major, minor); + return 0; +} + +static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used) +{ + uint32_t *p; + + *used = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) { + READ_BUF(8); + READ64(*used); + bitmap[1] &= ~FATTR4_WORD1_SPACE_USED; + } + dprintk("%s: space used=%Lu\n", __FUNCTION__, + (unsigned long long)*used); + return 0; +} + +static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) +{ + uint32_t *p; + uint64_t sec; + uint32_t nsec; + + READ_BUF(12); + READ64(sec); + READ32(nsec); + time->tv_sec = (time_t)sec; + time->tv_nsec = (long)nsec; + return 0; +} + +static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) +{ + int status = 0; + + time->tv_sec = 0; + time->tv_nsec = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) { + status = decode_attr_time(xdr, time); + bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS; + } + dprintk("%s: atime=%ld\n", __FUNCTION__, (long)time->tv_sec); + return status; +} + +static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) +{ + int status = 0; + + time->tv_sec = 0; + time->tv_nsec = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) { + status = decode_attr_time(xdr, time); + bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA; + } + dprintk("%s: ctime=%ld\n", __FUNCTION__, (long)time->tv_sec); + return status; +} + +static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) +{ + int status = 0; + + time->tv_sec = 0; + time->tv_nsec = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) { + status = decode_attr_time(xdr, time); + bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY; + } + dprintk("%s: mtime=%ld\n", __FUNCTION__, (long)time->tv_sec); + return status; +} + +static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t attrlen) +{ + unsigned int attrwords = XDR_QUADLEN(attrlen); + unsigned int nwords = xdr->p - savep; + + if (unlikely(attrwords != nwords)) { + printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n", + __FUNCTION__, + attrwords << 2, + (attrwords < nwords) ? '<' : '>', + nwords << 2); + return -EIO; + } + return 0; +} + static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { @@ -2092,6 +2439,69 @@ out_bad_bitmap: return -EIO; } +static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server) +{ + uint32_t *savep; + uint32_t attrlen, + bitmap[2] = {0}, + type; + int status, fmode = 0; + + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto xdr_error; + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto xdr_error; + + fattr->bitmap[0] = bitmap[0]; + fattr->bitmap[1] = bitmap[1]; + + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) + goto xdr_error; + + + if ((status = decode_attr_type(xdr, bitmap, &type)) != 0) + goto xdr_error; + fattr->type = nfs_type2fmt[type].nfs2type; + fmode = nfs_type2fmt[type].mode; + + if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0) + goto xdr_error; + if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0) + goto xdr_error; + if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid_u.nfs4)) != 0) + goto xdr_error; + if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0) + goto xdr_error; + if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0) + goto xdr_error; + fattr->mode |= fmode; + if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0) + goto xdr_error; + if ((status = decode_attr_owner(xdr, bitmap, server->nfs4_state, &fattr->uid)) != 0) + goto xdr_error; + if ((status = decode_attr_group(xdr, bitmap, server->nfs4_state, &fattr->gid)) != 0) + goto xdr_error; + if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0) + goto xdr_error; + if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0) + goto xdr_error; + if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0) + goto xdr_error; + if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0) + goto xdr_error; + if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0) + goto xdr_error; + if ((status = verify_attr_len(xdr, savep, attrlen)) == 0) { + fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4; + fattr->timestamp = jiffies; + } +xdr_error: + if (status != 0) + printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + return status; +} + + static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) { @@ -2757,6 +3167,29 @@ out: return status; } +/* + * Decode GETATTR response + */ +static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_getfattr(&xdr, res->fattr, res->server); +out: + return status; + +} + + /* * Decode CLOSE response */ @@ -3266,6 +3699,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(LOCKT, enc_lockt, dec_lockt), PROC(LOCKU, enc_locku, dec_locku), PROC(ACCESS, enc_access, dec_access), + PROC(GETATTR, enc_getattr, dec_getattr), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 5165192d15e7..33bdd9a0d85c 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -304,6 +304,7 @@ enum { NFSPROC4_CLNT_LOCKT, NFSPROC4_CLNT_LOCKU, NFSPROC4_CLNT_ACCESS, + NFSPROC4_CLNT_GETATTR, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 94ac6db11699..65c6b94504e8 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -3,6 +3,11 @@ #include +struct nfs4_fsid { + __u64 major; + __u64 minor; +}; + struct nfs_fattr { unsigned short valid; /* which fields are valid */ __u64 pre_size; /* pre_op_attr.size */ @@ -26,10 +31,7 @@ struct nfs_fattr { dev_t rdev; union { __u64 nfs3; /* also nfs2 */ - struct { - __u64 major; - __u64 minor; - } nfs4; + struct nfs4_fsid nfs4; } fsid_u; __u64 fileid; struct timespec atime; @@ -528,6 +530,16 @@ struct nfs4_getattr { struct nfs_pathconf * gt_pathconf; /* response */ }; +struct nfs4_getattr_arg { + const struct nfs_fh * fh; + const u32 * bitmask; +}; + +struct nfs4_getattr_res { + const struct nfs_server * server; + struct nfs_fattr * fattr; +}; + struct nfs4_getfh { struct nfs_fh * gf_fhandle; /* response */ }; -- cgit v1.2.3 From efec5fa4566c0b75949bdbe790f765d8b17fae1e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:29:17 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating LOOKUP RPC calls. --- fs/nfs/nfs4proc.c | 39 ++++++++++++----------- fs/nfs/nfs4xdr.c | 85 +++++++++++++++++++++++++++++++++++++++---------- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 12 +++++++ 4 files changed, 102 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d3675dbbcdaf..3c168164e6cb 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -956,30 +956,31 @@ out: return status; } -static int -nfs4_proc_lookup(struct inode *dir, struct qstr *name, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) +static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, + struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - struct nfs4_compound compound; - struct nfs4_op ops[5]; - struct nfs_fattr dir_attr; - int status; - - dir_attr.valid = 0; + int status; + struct nfs4_lookup_arg args = { + .bitmask = nfs4_fattr_bitmap, + .dir_fh = NFS_FH(dir), + .name = name, + }; + struct nfs4_lookup_res res = { + .server = NFS_SERVER(dir), + .fattr = fattr, + .fh = fhandle, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], + .rpc_argp = &args, + .rpc_resp = &res, + }; + fattr->valid = 0; dprintk("NFS call lookup %s\n", name->name); - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "lookup"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_getattr(&compound, &dir_attr); - nfs4_setup_lookup(&compound, name); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - status = nfs4_call_compound(&compound, NULL, 0); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply lookup: %d\n", status); - - if (status >= 0) - status = nfs_refresh_inode(dir, &dir_attr); return nfs4_map_errors(status); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5baa7cb627e0..c707a4ad1267 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -81,7 +81,7 @@ static int nfs_stat_to_errno(int); #define decode_putrootfh_maxsz (op_decode_hdr_maxsz) #define encode_getfh_maxsz (op_encode_hdr_maxsz) #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ - (NFS4_FHSIZE >> 2)) + ((3+NFS4_FHSIZE) >> 2)) #define encode_getattr_maxsz (op_encode_hdr_maxsz + 3) #define nfs4_fattr_bitmap_maxsz (26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2)) #define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \ @@ -109,7 +109,8 @@ static int nfs_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 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 + \ @@ -251,6 +252,16 @@ static int nfs_stat_to_errno(int); #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_getattr_maxsz) +#define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_lookup_maxsz + \ + encode_getattr_maxsz + \ + encode_getfh_maxsz) +#define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + \ + decode_getattr_maxsz + \ + decode_getfh_maxsz) @@ -665,16 +676,15 @@ encode_locku(struct xdr_stream *xdr, struct nfs_lockargs *arg) return 0; } -static int -encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup) +static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name) { - int len = lookup->lo_name->len; + int len = name->len; uint32_t *p; RESERVE_SPACE(8 + len); WRITE32(OP_LOOKUP); WRITE32(len); - WRITEMEM(lookup->lo_name->name, len); + WRITEMEM(name->name, len); return 0; } @@ -1079,7 +1089,7 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs status = encode_link(xdr, &cp->ops[i].u.link); break; case OP_LOOKUP: - status = encode_lookup(xdr, &cp->ops[i].u.lookup); + status = encode_lookup(xdr, cp->ops[i].u.lookup.lo_name); break; case OP_PUTFH: status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle); @@ -1151,6 +1161,30 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct n return status; } +/* + * Encode LOOKUP request + */ +static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 4, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) + goto out; + if ((status = encode_lookup(&xdr, args->name)) != 0) + goto out; + if ((status = encode_getfh(&xdr)) != 0) + goto out; + status = encode_getfattr(&xdr, args->bitmask); +out: + return status; +} + /* * Encode GETATTR request */ @@ -2376,10 +2410,8 @@ out_bad_bitmap: return -EIO; } -static int -decode_getfh(struct xdr_stream *xdr, struct nfs4_getfh *getfh) +static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) { - struct nfs_fh *fh = getfh->gf_fhandle; uint32_t *p; uint32_t len; int status; @@ -2392,7 +2424,7 @@ decode_getfh(struct xdr_stream *xdr, struct nfs4_getfh *getfh) READ_BUF(4); READ32(len); - if (len > NFS_MAXFHSIZE) + if (len > NFS4_FHSIZE) return -EIO; fh->size = len; READ_BUF(len); @@ -2865,7 +2897,7 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs status = decode_getattr(xdr, &op->u.getattr, cp->server); break; case OP_GETFH: - status = decode_getfh(xdr, &op->u.getfh); + status = decode_getfh(xdr, op->u.getfh.gf_fhandle); break; case OP_LINK: status = decode_link(xdr, &op->u.link); @@ -2973,6 +3005,29 @@ out: return status; } +/* + * Decode LOOKUP response + */ +static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) + goto out; + if ((status = decode_putfh(&xdr)) != 0) + goto out; + if ((status = decode_lookup(&xdr)) != 0) + goto out; + if ((status = decode_getfh(&xdr, res->fh)) != 0) + goto out; + status = decode_getfattr(&xdr, res->fattr, res->server); +out: + return status; +} + /* * Decode GETATTR response */ @@ -3026,9 +3081,6 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) { struct xdr_stream xdr; struct compound_hdr hdr; - struct nfs4_getfh gfh = { - .gf_fhandle = &res->fh, - }; int status; xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); @@ -3047,7 +3099,7 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) status = decode_getattr(&xdr, res->f_getattr, res->server); if (status) goto out; - status = decode_getfh(&xdr, &gfh); + status = decode_getfh(&xdr, &res->fh); if (status) goto out; status = decode_restorefh(&xdr); @@ -3485,6 +3537,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(LOCKU, enc_locku, dec_locku), PROC(ACCESS, enc_access, dec_access), PROC(GETATTR, enc_getattr, dec_getattr), + PROC(LOOKUP, enc_lookup, dec_lookup), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 33bdd9a0d85c..185998ba896c 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -305,6 +305,7 @@ enum { NFSPROC4_CLNT_LOCKU, NFSPROC4_CLNT_ACCESS, NFSPROC4_CLNT_GETATTR, + NFSPROC4_CLNT_LOOKUP, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 65c6b94504e8..b94596199ecb 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -554,6 +554,18 @@ struct nfs4_lookup { struct qstr * lo_name; /* request */ }; +struct nfs4_lookup_arg { + const struct nfs_fh * dir_fh; + const struct qstr * name; + const u32 * bitmask; +}; + +struct nfs4_lookup_res { + const struct nfs_server * server; + struct nfs_fattr * fattr; + struct nfs_fh * fh; +}; + struct nfs4_open { struct nfs4_client * op_client_state; /* request */ u32 op_share_access; /* request */ -- cgit v1.2.3 From fba5d3c4dcd1fa79698728c26bef24f15b9f2f41 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:30:19 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for looking up the mountpoint. --- fs/nfs/nfs4proc.c | 100 +++++++++++++++++++++++++++--------------------- fs/nfs/nfs4xdr.c | 62 ++++++++++++++++++++++++------ include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 9 ++--- 4 files changed, 111 insertions(+), 61 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3c168164e6cb..e27f51d7d4b6 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -54,7 +54,7 @@ #define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name #define OPNUM(cp) cp->ops[cp->req_nops].opnum -static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); +static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; @@ -252,17 +252,6 @@ nfs4_setup_link(struct nfs4_compound *cp, struct qstr *name, cp->req_nops++; } -static void -nfs4_setup_lookup(struct nfs4_compound *cp, struct qstr *q) -{ - struct nfs4_lookup *lookup = GET_OP(cp, lookup); - - lookup->lo_name = q; - - OPNUM(cp) = OP_LOOKUP; - cp->req_nops++; -} - static void nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) { @@ -274,13 +263,6 @@ nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) cp->req_nops++; } -static void -nfs4_setup_putrootfh(struct nfs4_compound *cp) -{ - OPNUM(cp) = OP_PUTROOTFH; - cp->req_nops++; -} - static void nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, struct page **pages, unsigned int bufsize, struct dentry *dentry) @@ -821,30 +803,60 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) return 0; } -static int -nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fsinfo *info) +static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *info) +{ + struct nfs_fattr * fattr = info->fattr; + struct nfs4_lookup_root_arg args = { + .bitmask = nfs4_fattr_bitmap, + }; + struct nfs4_lookup_res res = { + .server = server, + .fattr = fattr, + .fh = fhandle, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT], + .rpc_argp = &args, + .rpc_resp = &res, + }; + fattr->valid = 0; + return rpc_call_sync(server->client, &msg, 0); +} + +static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *info) { - struct nfs4_compound compound; - struct nfs4_op ops[4]; struct nfs_fattr * fattr = info->fattr; unsigned char * p; struct qstr q; - int status; + struct nfs4_lookup_arg args = { + .dir_fh = fhandle, + .name = &q, + .bitmask = nfs4_fattr_bitmap, + }; + 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, + }; + int status; /* * Now we do a separate LOOKUP for each component of the mount path. * The LOOKUPs are done separately so that we can conveniently * catch an ERR_WRONGSEC if it occurs along the way... */ - p = server->mnt_path; - fattr->valid = 0; - nfs4_setup_compound(&compound, ops, server, "getrootfh"); - nfs4_setup_putrootfh(&compound); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - if ((status = nfs4_call_compound(&compound, NULL, 0))) + status = nfs4_lookup_root(server, fhandle, info); + if (status) goto out; + + p = server->mnt_path; for (;;) { while (*p == '/') p++; @@ -856,12 +868,7 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, q.len = p - q.name; fattr->valid = 0; - nfs4_setup_compound(&compound, ops, server, "mount"); - nfs4_setup_putfh(&compound, fhandle); - nfs4_setup_lookup(&compound, &q); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - status = nfs4_call_compound(&compound, NULL, 0); + status = rpc_call_sync(server->client, &msg, 0); if (!status) continue; if (status == -ENOENT) { @@ -870,10 +877,10 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, } break; } + if (status == 0) + status = nfs4_do_fsinfo(server, fhandle, info); out: - if (status) - return nfs4_map_errors(status); - return nfs4_proc_fsinfo(server, fhandle, info); + return nfs4_map_errors(status); } static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) @@ -1468,9 +1475,8 @@ nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); } -static int -nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fsinfo *fsinfo) +static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *fsinfo) { struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], @@ -1481,6 +1487,12 @@ nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); } +static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) +{ + fsinfo->fattr->valid = 0; + return nfs4_map_errors(nfs4_do_fsinfo(server, fhandle, fsinfo)); +} + static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_pathconf *pathconf) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index c707a4ad1267..b2ab0246803d 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -262,6 +262,14 @@ static int nfs_stat_to_errno(int); op_decode_hdr_maxsz + \ decode_getattr_maxsz + \ decode_getfh_maxsz) +#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ + encode_putrootfh_maxsz + \ + encode_getattr_maxsz + \ + encode_getfh_maxsz) +#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ + decode_putrootfh_maxsz + \ + decode_getattr_maxsz + \ + decode_getfh_maxsz) @@ -1088,15 +1096,9 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_LINK: status = encode_link(xdr, &cp->ops[i].u.link); break; - case OP_LOOKUP: - status = encode_lookup(xdr, cp->ops[i].u.lookup.lo_name); - break; case OP_PUTFH: status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle); break; - case OP_PUTROOTFH: - status = encode_putrootfh(xdr); - break; case OP_READDIR: status = encode_readdir(xdr, &cp->ops[i].u.readdir, req); break; @@ -1185,6 +1187,27 @@ out: return status; } +/* + * Encode LOOKUP_ROOT request + */ +static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 3, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putrootfh(&xdr)) != 0) + goto out; + if ((status = encode_getfh(&xdr)) == 0) + status = encode_getfattr(&xdr, args->bitmask); +out: + return status; +} + /* * Encode GETATTR request */ @@ -2902,15 +2925,9 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_LINK: status = decode_link(xdr, &op->u.link); break; - case OP_LOOKUP: - status = decode_lookup(xdr); - break; case OP_PUTFH: status = decode_putfh(xdr); break; - case OP_PUTROOTFH: - status = decode_putrootfh(xdr); - break; case OP_READDIR: status = decode_readdir(xdr, req, &op->u.readdir); break; @@ -3028,6 +3045,26 @@ out: return status; } +/* + * Decode LOOKUP_ROOT response + */ +static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) + goto out; + if ((status = decode_putrootfh(&xdr)) != 0) + goto out; + if ((status = decode_getfh(&xdr, res->fh)) == 0) + status = decode_getfattr(&xdr, res->fattr, res->server); +out: + return status; +} + /* * Decode GETATTR response */ @@ -3538,6 +3575,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(ACCESS, enc_access, dec_access), PROC(GETATTR, enc_getattr, dec_getattr), PROC(LOOKUP, enc_lookup, dec_lookup), + PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 185998ba896c..1282973f8ffe 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -306,6 +306,7 @@ enum { NFSPROC4_CLNT_ACCESS, NFSPROC4_CLNT_GETATTR, NFSPROC4_CLNT_LOOKUP, + NFSPROC4_CLNT_LOOKUP_ROOT, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index b94596199ecb..d62d9089f6b8 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -550,10 +550,6 @@ struct nfs4_link { struct nfs4_change_info * ln_cinfo; /* response */ }; -struct nfs4_lookup { - struct qstr * lo_name; /* request */ -}; - struct nfs4_lookup_arg { const struct nfs_fh * dir_fh; const struct qstr * name; @@ -566,6 +562,10 @@ struct nfs4_lookup_res { struct nfs_fh * fh; }; +struct nfs4_lookup_root_arg { + const u32 * bitmask; +}; + struct nfs4_open { struct nfs4_client * op_client_state; /* request */ u32 op_share_access; /* request */ @@ -644,7 +644,6 @@ struct nfs4_op { struct nfs4_getattr getattr; struct nfs4_getfh getfh; struct nfs4_link link; - struct nfs4_lookup lookup; struct nfs4_open open; struct nfs4_open_confirm open_confirm; struct nfs4_putfh putfh; -- cgit v1.2.3 From c8e46334ca284863a76174719a617f392d8941cc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:31:33 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating REMOVE RPC calls. --- fs/nfs/nfs4proc.c | 42 ++++++++++++++++++--------------- fs/nfs/nfs4xdr.c | 63 +++++++++++++++++++++++++++++++++++++++++-------- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 8 +++++-- 4 files changed, 83 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e27f51d7d4b6..9379abe335ba 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -340,8 +340,7 @@ nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_chang { struct nfs4_remove *remove = GET_OP(cp, remove); - remove->rm_namelen = name->len; - remove->rm_name = name->name; + remove->name = name; remove->rm_cinfo = cinfo; OPNUM(cp) = OP_REMOVE; @@ -443,6 +442,14 @@ process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr) } } +static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinfo) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + if (cinfo->before == nfsi->change_attr && cinfo->atomic) + nfsi->change_attr = cinfo->after; +} + /* * OPEN_RECLAIM: * reclaim state on the server after a reboot. @@ -1218,26 +1225,23 @@ nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, return inode; } -static int -nfs4_proc_remove(struct inode *dir, struct qstr *name) +static int nfs4_proc_remove(struct inode *dir, struct qstr *name) { - struct nfs4_compound compound; - struct nfs4_op ops[3]; - struct nfs4_change_info dir_cinfo; - struct nfs_fattr dir_attr; + struct nfs4_remove_arg args = { + .fh = NFS_FH(dir), + .name = name, + }; + struct nfs4_change_info res; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], + .rpc_argp = &args, + .rpc_resp = &res, + }; int status; - dir_attr.valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "remove"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_remove(&compound, name, &dir_cinfo); - nfs4_setup_getattr(&compound, &dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); - - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); - } + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (status == 0) + update_changeattr(dir, &res); return nfs4_map_errors(status); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index b2ab0246803d..8028be7b9391 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -111,6 +111,8 @@ static int nfs_stat_to_errno(int); (op_decode_hdr_maxsz) #define encode_lookup_maxsz (op_encode_hdr_maxsz + \ 1 + ((3 + NFS4_FHSIZE) >> 2)) +#define encode_remove_maxsz (op_encode_hdr_maxsz + \ + 1 + ((3 + NFS4_MAXNAMLEN) >> 2)) #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 + \ @@ -270,6 +272,12 @@ static int nfs_stat_to_errno(int); decode_putrootfh_maxsz + \ decode_getattr_maxsz + \ decode_getfh_maxsz) +#define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_remove_maxsz) +#define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 5) @@ -927,15 +935,14 @@ encode_readlink(struct xdr_stream *xdr, struct nfs4_readlink *readlink, struct r return 0; } -static int -encode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove) +static int encode_remove(struct xdr_stream *xdr, const struct qstr *name) { uint32_t *p; - RESERVE_SPACE(8 + remove->rm_namelen); + RESERVE_SPACE(8 + name->len); WRITE32(OP_REMOVE); - WRITE32(remove->rm_namelen); - WRITEMEM(remove->rm_name, remove->rm_namelen); + WRITE32(name->len); + WRITEMEM(name->name, name->len); return 0; } @@ -1106,7 +1113,7 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs status = encode_readlink(xdr, &cp->ops[i].u.readlink, req); break; case OP_REMOVE: - status = encode_remove(xdr, &cp->ops[i].u.remove); + status = encode_remove(xdr, cp->ops[i].u.remove.name); break; case OP_RENAME: status = encode_rename(xdr, &cp->ops[i].u.rename); @@ -1208,6 +1215,24 @@ out: return status; } +/* + * Encode REMOVE request + */ +static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putfh(&xdr, args->fh)) == 0) + status = encode_remove(&xdr, args->name); + return status; +} + /* * Encode GETATTR request */ @@ -2763,15 +2788,14 @@ decode_restorefh(struct xdr_stream *xdr) return decode_op_hdr(xdr, OP_RESTOREFH); } -static int -decode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove) +static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { int status; status = decode_op_hdr(xdr, OP_REMOVE); if (status) goto out; - status = decode_change_info(xdr, remove->rm_cinfo); + status = decode_change_info(xdr, cinfo); out: return status; } @@ -2938,7 +2962,7 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs status = decode_restorefh(xdr); break; case OP_REMOVE: - status = decode_remove(xdr, &op->u.remove); + status = decode_remove(xdr, op->u.remove.rm_cinfo); break; case OP_RENAME: status = decode_rename(xdr, &op->u.rename); @@ -3065,6 +3089,24 @@ out: return status; } +/* + * Decode REMOVE response + */ +static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) + goto out; + if ((status = decode_putfh(&xdr)) == 0) + status = decode_remove(&xdr, cinfo); +out: + return status; +} + /* * Decode GETATTR response */ @@ -3576,6 +3618,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(GETATTR, enc_getattr, dec_getattr), PROC(LOOKUP, enc_lookup, dec_lookup), PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root), + PROC(REMOVE, enc_remove, dec_remove), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 1282973f8ffe..e2419d5ced3a 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -307,6 +307,7 @@ enum { NFSPROC4_CLNT_GETATTR, NFSPROC4_CLNT_LOOKUP, NFSPROC4_CLNT_LOOKUP_ROOT, + NFSPROC4_CLNT_REMOVE, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index d62d9089f6b8..51046207c1cb 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -607,11 +607,15 @@ struct nfs4_readlink { }; struct nfs4_remove { - u32 rm_namelen; /* request */ - const char * rm_name; /* request */ + struct qstr * name; /* request */ struct nfs4_change_info * rm_cinfo; /* response */ }; +struct nfs4_remove_arg { + const struct nfs_fh * fh; + const struct qstr * name; +}; + struct nfs4_rename { u32 rn_oldnamelen; /* request */ const char * rn_oldname; /* request */ -- cgit v1.2.3 From 6aedfa2dd5cf85bcd4ccc79af920b2bcb3a10101 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:32:26 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating RENAME RPC calls. --- fs/nfs/nfs4proc.c | 57 +++++++++--------------------- fs/nfs/nfs4xdr.c | 92 ++++++++++++++++++++++++++++++++++++++----------- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 18 +++++----- 4 files changed, 100 insertions(+), 68 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9379abe335ba..182af63a88b1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -347,23 +347,6 @@ nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_chang cp->req_nops++; } -static void -nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new, - struct nfs4_change_info *old_cinfo, struct nfs4_change_info *new_cinfo) -{ - struct nfs4_rename *rename = GET_OP(cp, rename); - - rename->rn_oldnamelen = old->len; - rename->rn_oldname = old->name; - rename->rn_newnamelen = new->len; - rename->rn_newname = new->name; - rename->rn_src_cinfo = old_cinfo; - rename->rn_dst_cinfo = new_cinfo; - - OPNUM(cp) = OP_RENAME; - cp->req_nops++; -} - static void nfs4_setup_restorefh(struct nfs4_compound *cp) { @@ -1291,34 +1274,28 @@ nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) return 0; } -static int -nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, - struct inode *new_dir, struct qstr *new_name) +static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, + struct inode *new_dir, struct qstr *new_name) { - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs4_change_info old_cinfo, new_cinfo; - struct nfs_fattr old_dir_attr, new_dir_attr; + struct nfs4_rename_arg arg = { + .old_dir = NFS_FH(old_dir), + .new_dir = NFS_FH(new_dir), + .old_name = old_name, + .new_name = new_name, + }; + struct nfs4_rename_res res = { }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], + .rpc_argp = &arg, + .rpc_resp = &res, + }; int status; - - old_dir_attr.valid = 0; - new_dir_attr.valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(old_dir), "rename"); - nfs4_setup_putfh(&compound, NFS_FH(old_dir)); - nfs4_setup_savefh(&compound); - nfs4_setup_putfh(&compound, NFS_FH(new_dir)); - nfs4_setup_rename(&compound, old_name, new_name, &old_cinfo, &new_cinfo); - nfs4_setup_getattr(&compound, &new_dir_attr); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &old_dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); + status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); if (!status) { - process_cinfo(&old_cinfo, &old_dir_attr); - process_cinfo(&new_cinfo, &new_dir_attr); - nfs_refresh_inode(old_dir, &old_dir_attr); - nfs_refresh_inode(new_dir, &new_dir_attr); + update_changeattr(old_dir, &res.old_cinfo); + update_changeattr(new_dir, &res.new_cinfo); } return nfs4_map_errors(status); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 8028be7b9391..afdfd5dd635d 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -113,6 +113,9 @@ static int nfs_stat_to_errno(int); 1 + ((3 + NFS4_FHSIZE) >> 2)) #define encode_remove_maxsz (op_encode_hdr_maxsz + \ 1 + ((3 + NFS4_MAXNAMLEN) >> 2)) +#define encode_rename_maxsz (op_encode_hdr_maxsz + \ + 2 * (1 + ((3 + NFS4_MAXNAMLEN) >> 2))) +#define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5) #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 + \ @@ -278,6 +281,16 @@ static int nfs_stat_to_errno(int); #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ op_decode_hdr_maxsz + 5) +#define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_savefh_maxsz + \ + encode_putfh_maxsz + \ + encode_rename_maxsz) +#define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_savefh_maxsz + \ + decode_putfh_maxsz + \ + decode_rename_maxsz) @@ -947,19 +960,18 @@ static int encode_remove(struct xdr_stream *xdr, const struct qstr *name) return 0; } -static int -encode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename) +static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname) { uint32_t *p; - RESERVE_SPACE(8 + rename->rn_oldnamelen); + RESERVE_SPACE(8 + oldname->len); WRITE32(OP_RENAME); - WRITE32(rename->rn_oldnamelen); - WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen); + WRITE32(oldname->len); + WRITEMEM(oldname->name, oldname->len); - RESERVE_SPACE(4 + rename->rn_newnamelen); - WRITE32(rename->rn_newnamelen); - WRITEMEM(rename->rn_newname, rename->rn_newnamelen); + RESERVE_SPACE(4 + newname->len); + WRITE32(newname->len); + WRITEMEM(newname->name, newname->len); return 0; } @@ -1115,9 +1127,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_REMOVE: status = encode_remove(xdr, cp->ops[i].u.remove.name); break; - case OP_RENAME: - status = encode_rename(xdr, &cp->ops[i].u.rename); - break; case OP_RESTOREFH: status = encode_restorefh(xdr); break; @@ -1233,6 +1242,30 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct n return status; } +/* + * Encode RENAME request + */ +static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 4, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putfh(&xdr, args->old_dir)) != 0) + goto out; + if ((status = encode_savefh(&xdr)) != 0) + goto out; + if ((status = encode_putfh(&xdr, args->new_dir)) != 0) + goto out; + status = encode_rename(&xdr, args->old_name, args->new_name); +out: + return status; +} + /* * Encode GETATTR request */ @@ -2095,7 +2128,6 @@ decode_create(struct xdr_stream *xdr, struct nfs4_create *create) return 0; } -extern uint32_t nfs4_fattr_bitmap[2]; extern uint32_t nfs4_fsstat_bitmap[2]; extern uint32_t nfs4_pathconf_bitmap[2]; @@ -2800,18 +2832,17 @@ out: return status; } -static int -decode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename) +static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo, + struct nfs4_change_info *new_cinfo) { int status; status = decode_op_hdr(xdr, OP_RENAME); if (status) goto out; - if ((status = decode_change_info(xdr, rename->rn_src_cinfo))) - goto out; - if ((status = decode_change_info(xdr, rename->rn_dst_cinfo))) + if ((status = decode_change_info(xdr, old_cinfo))) goto out; + status = decode_change_info(xdr, new_cinfo); out: return status; } @@ -2964,9 +2995,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_REMOVE: status = decode_remove(xdr, op->u.remove.rm_cinfo); break; - case OP_RENAME: - status = decode_rename(xdr, &op->u.rename); - break; case OP_SAVEFH: status = decode_savefh(xdr); break; @@ -3107,6 +3135,29 @@ out: return status; } +/* + * Decode RENAME response + */ +static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_rename_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) + goto out; + if ((status = decode_putfh(&xdr)) != 0) + goto out; + if ((status = decode_savefh(&xdr)) != 0) + goto out; + if ((status = decode_putfh(&xdr)) != 0) + goto out; + status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo); +out: + return status; +} + /* * Decode GETATTR response */ @@ -3619,6 +3670,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(LOOKUP, enc_lookup, dec_lookup), PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root), PROC(REMOVE, enc_remove, dec_remove), + PROC(RENAME, enc_rename, dec_rename), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index e2419d5ced3a..c747854ee32e 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -308,6 +308,7 @@ enum { NFSPROC4_CLNT_LOOKUP, NFSPROC4_CLNT_LOOKUP_ROOT, NFSPROC4_CLNT_REMOVE, + NFSPROC4_CLNT_RENAME, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 51046207c1cb..c87aa64a75aa 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -616,13 +616,16 @@ struct nfs4_remove_arg { const struct qstr * name; }; -struct nfs4_rename { - u32 rn_oldnamelen; /* request */ - const char * rn_oldname; /* request */ - u32 rn_newnamelen; /* request */ - const char * rn_newname; /* request */ - struct nfs4_change_info * rn_src_cinfo; /* response */ - struct nfs4_change_info * rn_dst_cinfo; /* response */ +struct nfs4_rename_arg { + const struct nfs_fh * old_dir; + const struct nfs_fh * new_dir; + const struct qstr * old_name; + const struct qstr * new_name; +}; + +struct nfs4_rename_res { + struct nfs4_change_info old_cinfo; + struct nfs4_change_info new_cinfo; }; struct nfs4_setattr { @@ -654,7 +657,6 @@ struct nfs4_op { struct nfs4_readdir readdir; struct nfs4_readlink readlink; struct nfs4_remove remove; - struct nfs4_rename rename; struct nfs4_client * renew; struct nfs4_setattr setattr; } u; -- cgit v1.2.3 From 4e7473b804fd25415fbb58ba3452ec13d889da8a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:33:21 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for hard linking --- fs/nfs/nfs4proc.c | 54 ++++++++++----------------------- fs/nfs/nfs4xdr.c | 81 ++++++++++++++++++++++++++++++++++++++++--------- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 9 +++--- 4 files changed, 88 insertions(+), 57 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 182af63a88b1..6aff8096d7e7 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -238,20 +238,6 @@ nfs4_setup_getfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) cp->req_nops++; } -static void -nfs4_setup_link(struct nfs4_compound *cp, struct qstr *name, - struct nfs4_change_info *info) -{ - struct nfs4_link *link = GET_OP(cp, link); - - link->ln_namelen = name->len; - link->ln_name = name->name; - link->ln_cinfo = info; - - OPNUM(cp) = OP_LINK; - cp->req_nops++; -} - static void nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) { @@ -1300,33 +1286,25 @@ static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, return nfs4_map_errors(status); } -static int -nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) +static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs4_change_info dir_cinfo; - struct nfs_fattr dir_attr, fattr; + struct nfs4_link_arg arg = { + .fh = NFS_FH(inode), + .dir_fh = NFS_FH(dir), + .name = name, + }; + struct nfs4_change_info cinfo = { }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], + .rpc_argp = &arg, + .rpc_resp = &cinfo, + }; int status; - - dir_attr.valid = 0; - fattr.valid = 0; - - nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "link"); - nfs4_setup_putfh(&compound, NFS_FH(inode)); - nfs4_setup_savefh(&compound); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_link(&compound, name, &dir_cinfo); - nfs4_setup_getattr(&compound, &dir_attr); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &fattr); - status = nfs4_call_compound(&compound, NULL, 0); - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); - nfs_refresh_inode(inode, &fattr); - } + status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + if (!status) + update_changeattr(dir, &cinfo); + return nfs4_map_errors(status); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index afdfd5dd635d..99165059d6db 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -116,6 +116,9 @@ static int nfs_stat_to_errno(int); #define encode_rename_maxsz (op_encode_hdr_maxsz + \ 2 * (1 + ((3 + NFS4_MAXNAMLEN) >> 2))) #define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5) +#define encode_link_maxsz (op_encode_hdr_maxsz + \ + 1 + ((3 + NFS4_MAXNAMLEN) >> 2)) +#define decode_link_maxsz (op_decode_hdr_maxsz + 5) #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 + \ @@ -291,6 +294,16 @@ static int nfs_stat_to_errno(int); decode_savefh_maxsz + \ decode_putfh_maxsz + \ decode_rename_maxsz) +#define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_savefh_maxsz + \ + encode_putfh_maxsz + \ + encode_link_maxsz) +#define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_savefh_maxsz + \ + decode_putfh_maxsz + \ + decode_link_maxsz) @@ -618,15 +631,14 @@ encode_getfh(struct xdr_stream *xdr) return 0; } -static int -encode_link(struct xdr_stream *xdr, struct nfs4_link *link) +static int encode_link(struct xdr_stream *xdr, const struct qstr *name) { uint32_t *p; - RESERVE_SPACE(8 + link->ln_namelen); + RESERVE_SPACE(8 + name->len); WRITE32(OP_LINK); - WRITE32(link->ln_namelen); - WRITEMEM(link->ln_name, link->ln_namelen); + WRITE32(name->len); + WRITEMEM(name->name, name->len); return 0; } @@ -1112,9 +1124,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_GETFH: status = encode_getfh(xdr); break; - case OP_LINK: - status = encode_link(xdr, &cp->ops[i].u.link); - break; case OP_PUTFH: status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle); break; @@ -1266,6 +1275,30 @@ out: return status; } +/* + * Encode LINK request + */ +static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 4, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putfh(&xdr, args->fh)) != 0) + goto out; + if ((status = encode_savefh(&xdr)) != 0) + goto out; + if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) + goto out; + status = encode_link(&xdr, args->name); +out: + return status; +} + /* * Encode GETATTR request */ @@ -2512,15 +2545,14 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) return 0; } -static int -decode_link(struct xdr_stream *xdr, struct nfs4_link *link) +static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { int status; status = decode_op_hdr(xdr, OP_LINK); if (status) return status; - return decode_change_info(xdr, link->ln_cinfo); + return decode_change_info(xdr, cinfo); } /* @@ -2977,9 +3009,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_GETFH: status = decode_getfh(xdr, op->u.getfh.gf_fhandle); break; - case OP_LINK: - status = decode_link(xdr, &op->u.link); - break; case OP_PUTFH: status = decode_putfh(xdr); break; @@ -3158,6 +3187,29 @@ out: return status; } +/* + * Decode LINK response + */ +static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) + goto out; + if ((status = decode_putfh(&xdr)) != 0) + goto out; + if ((status = decode_savefh(&xdr)) != 0) + goto out; + if ((status = decode_putfh(&xdr)) != 0) + goto out; + status = decode_link(&xdr, cinfo); +out: + return status; +} + /* * Decode GETATTR response */ @@ -3671,6 +3723,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root), PROC(REMOVE, enc_remove, dec_remove), PROC(RENAME, enc_rename, dec_rename), + PROC(LINK, enc_link, dec_link), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index c747854ee32e..70cc1ff739dc 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -309,6 +309,7 @@ enum { NFSPROC4_CLNT_LOOKUP_ROOT, NFSPROC4_CLNT_REMOVE, NFSPROC4_CLNT_RENAME, + NFSPROC4_CLNT_LINK, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index c87aa64a75aa..864f742f3b1f 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -544,10 +544,10 @@ struct nfs4_getfh { struct nfs_fh * gf_fhandle; /* response */ }; -struct nfs4_link { - u32 ln_namelen; /* request */ - const char * ln_name; /* request */ - struct nfs4_change_info * ln_cinfo; /* response */ +struct nfs4_link_arg { + const struct nfs_fh * fh; + const struct nfs_fh * dir_fh; + const struct qstr * name; }; struct nfs4_lookup_arg { @@ -650,7 +650,6 @@ struct nfs4_op { struct nfs4_create create; struct nfs4_getattr getattr; struct nfs4_getfh getfh; - struct nfs4_link link; struct nfs4_open open; struct nfs4_open_confirm open_confirm; struct nfs4_putfh putfh; -- cgit v1.2.3 From 4e55f94bcda6f49994ff9da514ced664a9908d46 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:34:14 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating CREATE RPC calls. --- fs/nfs/nfs4proc.c | 250 +++++++++++++++++------------------------------- fs/nfs/nfs4xdr.c | 130 +++++++++++++++---------- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 35 +++---- 4 files changed, 190 insertions(+), 226 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6aff8096d7e7..2693f8bdbec5 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -81,76 +81,6 @@ nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops, cp->server = server; } -static void -nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name, - struct iattr *sattr, struct nfs4_change_info *info) -{ - struct nfs4_create *create = GET_OP(cp, create); - - create->cr_ftype = NF4DIR; - create->cr_namelen = name->len; - create->cr_name = name->name; - create->cr_attrs = sattr; - create->cr_cinfo = info; - - OPNUM(cp) = OP_CREATE; - cp->req_nops++; -} - -static void -nfs4_setup_create_symlink(struct nfs4_compound *cp, struct qstr *name, - struct qstr *linktext, struct iattr *sattr, - struct nfs4_change_info *info) -{ - struct nfs4_create *create = GET_OP(cp, create); - - create->cr_ftype = NF4LNK; - create->cr_textlen = linktext->len; - create->cr_text = linktext->name; - create->cr_namelen = name->len; - create->cr_name = name->name; - create->cr_attrs = sattr; - create->cr_cinfo = info; - - OPNUM(cp) = OP_CREATE; - cp->req_nops++; -} - -static void -nfs4_setup_create_special(struct nfs4_compound *cp, struct qstr *name, - dev_t dev, struct iattr *sattr, - struct nfs4_change_info *info) -{ - int mode = sattr->ia_mode; - struct nfs4_create *create = GET_OP(cp, create); - - BUG_ON(!(sattr->ia_valid & ATTR_MODE)); - BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); - - if (S_ISFIFO(mode)) - create->cr_ftype = NF4FIFO; - else if (S_ISBLK(mode)) { - create->cr_ftype = NF4BLK; - create->cr_specdata1 = MAJOR(dev); - create->cr_specdata2 = MINOR(dev); - } - else if (S_ISCHR(mode)) { - create->cr_ftype = NF4CHR; - create->cr_specdata1 = MAJOR(dev); - create->cr_specdata2 = MINOR(dev); - } - else - create->cr_ftype = NF4SOCK; - - create->cr_namelen = name->len; - create->cr_name = name->name; - create->cr_attrs = sattr; - create->cr_cinfo = info; - - OPNUM(cp) = OP_CREATE; - cp->req_nops++; -} - /* * This is our standard bitmap for GETATTR requests. */ @@ -227,17 +157,6 @@ nfs4_setup_pathconf(struct nfs4_compound *cp, NULL, NULL, pathconf); } -static void -nfs4_setup_getfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) -{ - struct nfs4_getfh *getfh = GET_OP(cp, getfh); - - getfh->gf_fhandle = fhandle; - - OPNUM(cp) = OP_GETFH; - cp->req_nops++; -} - static void nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) { @@ -333,20 +252,6 @@ nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_chang cp->req_nops++; } -static void -nfs4_setup_restorefh(struct nfs4_compound *cp) -{ - OPNUM(cp) = OP_RESTOREFH; - cp->req_nops++; -} - -static void -nfs4_setup_savefh(struct nfs4_compound *cp) -{ - OPNUM(cp) = OP_SAVEFH; - cp->req_nops++; -} - static void renew_lease(struct nfs_server *server, unsigned long timestamp) { @@ -1308,64 +1213,68 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n return nfs4_map_errors(status); } -static int -nfs4_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, - struct iattr *sattr, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) +static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, + struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, + struct nfs_fattr *fattr) { - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs_fattr dir_attr; - struct nfs4_change_info dir_cinfo; + struct nfs4_create_arg arg = { + .dir_fh = NFS_FH(dir), + .server = NFS_SERVER(dir), + .name = name, + .attrs = sattr, + .ftype = NF4LNK, + .bitmask = nfs4_fattr_bitmap, + }; + struct nfs4_create_res res = { + .server = NFS_SERVER(dir), + .fh = fhandle, + .fattr = fattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; int status; - dir_attr.valid = 0; + arg.u.symlink = path; fattr->valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "symlink"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_savefh(&compound); - nfs4_setup_create_symlink(&compound, name, path, sattr, &dir_cinfo); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); - - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); - } + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (!status) + update_changeattr(dir, &res.dir_cinfo); return nfs4_map_errors(status); } -static int -nfs4_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) +static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name, + struct iattr *sattr, struct nfs_fh *fhandle, + struct nfs_fattr *fattr) { - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs_fattr dir_attr; - struct nfs4_change_info dir_cinfo; + struct nfs4_create_arg arg = { + .dir_fh = NFS_FH(dir), + .server = NFS_SERVER(dir), + .name = name, + .attrs = sattr, + .ftype = NF4DIR, + .bitmask = nfs4_fattr_bitmap, + }; + struct nfs4_create_res res = { + .server = NFS_SERVER(dir), + .fh = fhandle, + .fattr = fattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; int status; - dir_attr.valid = 0; fattr->valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mkdir"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_savefh(&compound); - nfs4_setup_create_dir(&compound, name, sattr, &dir_cinfo); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fhandle); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); - - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); - } + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (!status) + update_changeattr(dir, &res.dir_cinfo); return nfs4_map_errors(status); } @@ -1391,33 +1300,52 @@ nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, return nfs4_map_errors(status); } -static int -nfs4_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, - dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr) +static int nfs4_proc_mknod(struct inode *dir, struct qstr *name, + struct iattr *sattr, dev_t rdev, struct nfs_fh *fh, + struct nfs_fattr *fattr) { - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs_fattr dir_attr; - struct nfs4_change_info dir_cinfo; + struct nfs4_create_arg arg = { + .dir_fh = NFS_FH(dir), + .server = NFS_SERVER(dir), + .name = name, + .attrs = sattr, + .bitmask = nfs4_fattr_bitmap, + }; + struct nfs4_create_res res = { + .server = NFS_SERVER(dir), + .fh = fh, + .fattr = fattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; int status; + int mode = sattr->ia_mode; - dir_attr.valid = 0; fattr->valid = 0; - - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mknod"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_savefh(&compound); - nfs4_setup_create_special(&compound, name, rdev,sattr, &dir_cinfo); - nfs4_setup_getattr(&compound, fattr); - nfs4_setup_getfh(&compound, fh); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &dir_attr); - status = nfs4_call_compound(&compound, NULL, 0); - if (!status) { - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); + BUG_ON(!(sattr->ia_valid & ATTR_MODE)); + BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); + if (S_ISFIFO(mode)) + arg.ftype = NF4FIFO; + else if (S_ISBLK(mode)) { + arg.ftype = NF4BLK; + arg.u.device.specdata1 = MAJOR(rdev); + arg.u.device.specdata2 = MINOR(rdev); + } + else if (S_ISCHR(mode)) { + arg.ftype = NF4CHR; + arg.u.device.specdata1 = MAJOR(rdev); + arg.u.device.specdata2 = MINOR(rdev); } + else + arg.ftype = NF4SOCK; + + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + if (!status) + update_changeattr(dir, &res.dir_cinfo); return nfs4_map_errors(status); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 99165059d6db..1ab60b1dbf90 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -83,7 +83,8 @@ static int nfs_stat_to_errno(int); #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ ((3+NFS4_FHSIZE) >> 2)) #define encode_getattr_maxsz (op_encode_hdr_maxsz + 3) -#define nfs4_fattr_bitmap_maxsz (26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2)) +#define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) +#define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz) #define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \ nfs4_fattr_bitmap_maxsz) #define encode_savefh_maxsz (op_encode_hdr_maxsz) @@ -112,13 +113,17 @@ static int nfs_stat_to_errno(int); #define encode_lookup_maxsz (op_encode_hdr_maxsz + \ 1 + ((3 + NFS4_FHSIZE) >> 2)) #define encode_remove_maxsz (op_encode_hdr_maxsz + \ - 1 + ((3 + NFS4_MAXNAMLEN) >> 2)) + nfs4_name_maxsz) #define encode_rename_maxsz (op_encode_hdr_maxsz + \ - 2 * (1 + ((3 + NFS4_MAXNAMLEN) >> 2))) + 2 * nfs4_name_maxsz) #define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5) #define encode_link_maxsz (op_encode_hdr_maxsz + \ - 1 + ((3 + NFS4_MAXNAMLEN) >> 2)) + nfs4_name_maxsz) #define decode_link_maxsz (op_decode_hdr_maxsz + 5) +#define encode_create_maxsz (op_encode_hdr_maxsz + \ + 2 + 2 * nfs4_name_maxsz + \ + nfs4_fattr_bitmap_maxsz) +#define decode_create_maxsz (op_decode_hdr_maxsz + 8) #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 + \ @@ -304,6 +309,16 @@ static int nfs_stat_to_errno(int); decode_savefh_maxsz + \ decode_putfh_maxsz + \ decode_link_maxsz) +#define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_create_maxsz + \ + encode_getattr_maxsz + \ + encode_getfh_maxsz) +#define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_create_maxsz + \ + decode_getattr_maxsz + \ + decode_getfh_maxsz) @@ -370,9 +385,7 @@ encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) return 0; } -static int -encode_attrs(struct xdr_stream *xdr, struct iattr *iap, - struct nfs_server *server) +static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server) { char owner_name[IDMAP_NAMESZ]; char owner_group[IDMAP_NAMESZ]; @@ -536,38 +549,36 @@ encode_commit(struct xdr_stream *xdr, struct nfs_writeargs *args) return 0; } -static int -encode_create(struct xdr_stream *xdr, struct nfs4_create *create, - struct nfs_server *server) +static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create) { uint32_t *p; RESERVE_SPACE(8); WRITE32(OP_CREATE); - WRITE32(create->cr_ftype); + WRITE32(create->ftype); - switch (create->cr_ftype) { + switch (create->ftype) { case NF4LNK: - RESERVE_SPACE(4 + create->cr_textlen); - WRITE32(create->cr_textlen); - WRITEMEM(create->cr_text, create->cr_textlen); + RESERVE_SPACE(4 + create->u.symlink->len); + WRITE32(create->u.symlink->len); + WRITEMEM(create->u.symlink->name, create->u.symlink->len); break; case NF4BLK: case NF4CHR: RESERVE_SPACE(8); - WRITE32(create->cr_specdata1); - WRITE32(create->cr_specdata2); + WRITE32(create->u.device.specdata1); + WRITE32(create->u.device.specdata2); break; default: break; } - RESERVE_SPACE(4 + create->cr_namelen); - WRITE32(create->cr_namelen); - WRITEMEM(create->cr_name, create->cr_namelen); + RESERVE_SPACE(4 + create->name->len); + WRITE32(create->name->len); + WRITEMEM(create->name->name, create->name->len); - return encode_attrs(xdr, create->cr_attrs, server); + return encode_attrs(xdr, create->attrs, create->server); } static int @@ -1115,15 +1126,9 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs for (i = 0; i < cp->req_nops; i++) { switch (cp->ops[i].opnum) { - case OP_CREATE: - status = encode_create(xdr, &cp->ops[i].u.create, cp->server); - break; case OP_GETATTR: status = encode_getattr(xdr, &cp->ops[i].u.getattr); break; - case OP_GETFH: - status = encode_getfh(xdr); - break; case OP_PUTFH: status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle); break; @@ -1136,12 +1141,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_REMOVE: status = encode_remove(xdr, cp->ops[i].u.remove.name); break; - case OP_RESTOREFH: - status = encode_restorefh(xdr); - break; - case OP_SAVEFH: - status = encode_savefh(xdr); - break; default: BUG(); } @@ -1299,6 +1298,30 @@ out: return status; } +/* + * Encode CREATE request + */ +static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 4, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) + goto out; + if ((status = encode_create(&xdr, args)) != 0) + goto out; + if ((status = encode_getfattr(&xdr, args->bitmask)) != 0) + goto out; + status = encode_getfh(&xdr); +out: + return status; +} + /* * Encode GETATTR request */ @@ -2143,8 +2166,7 @@ decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) return 0; } -static int -decode_create(struct xdr_stream *xdr, struct nfs4_create *create) +static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { uint32_t *p; uint32_t bmlen; @@ -2153,7 +2175,7 @@ decode_create(struct xdr_stream *xdr, struct nfs4_create *create) status = decode_op_hdr(xdr, OP_CREATE); if (status) return status; - if ((status = decode_change_info(xdr, create->cr_cinfo))) + if ((status = decode_change_info(xdr, cinfo))) return status; READ_BUF(4); READ32(bmlen); @@ -3000,15 +3022,9 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs op = &cp->ops[0]; for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++, op++) { switch (op->opnum) { - case OP_CREATE: - status = decode_create(xdr, &op->u.create); - break; case OP_GETATTR: status = decode_getattr(xdr, &op->u.getattr, cp->server); break; - case OP_GETFH: - status = decode_getfh(xdr, op->u.getfh.gf_fhandle); - break; case OP_PUTFH: status = decode_putfh(xdr); break; @@ -3018,15 +3034,9 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_READLINK: status = decode_readlink(xdr, req, &op->u.readlink); break; - case OP_RESTOREFH: - status = decode_restorefh(xdr); - break; case OP_REMOVE: status = decode_remove(xdr, op->u.remove.rm_cinfo); break; - case OP_SAVEFH: - status = decode_savefh(xdr); - break; default: BUG(); return -EIO; @@ -3210,6 +3220,29 @@ out: return status; } +/* + * Decode CREATE response + */ +static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) + goto out; + if ((status = decode_putfh(&xdr)) != 0) + goto out; + if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0) + goto out; + if ((status = decode_getfattr(&xdr, res->fattr, res->server)) != 0) + goto out; + status = decode_getfh(&xdr, res->fh); +out: + return status; +} + /* * Decode GETATTR response */ @@ -3724,6 +3757,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(REMOVE, enc_remove, dec_remove), PROC(RENAME, enc_rename, dec_rename), PROC(LINK, enc_link, dec_link), + PROC(CREATE, enc_create, dec_create), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 70cc1ff739dc..6137a19830f0 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -310,6 +310,7 @@ enum { NFSPROC4_CLNT_REMOVE, NFSPROC4_CLNT_RENAME, NFSPROC4_CLNT_LINK, + NFSPROC4_CLNT_CREATE, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 864f742f3b1f..c423805bc7a0 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -501,23 +501,30 @@ struct nfs4_close { u32 cl_seqid; /* request */ }; -struct nfs4_create { - u32 cr_ftype; /* request */ - union { /* request */ - struct { - u32 textlen; - const char * text; - } symlink; /* NF4LNK */ +struct nfs4_create_arg { + u32 ftype; + union { + struct qstr * symlink; /* NF4LNK */ struct { u32 specdata1; u32 specdata2; } device; /* NF4BLK, NF4CHR */ } u; - u32 cr_namelen; /* request */ - const char * cr_name; /* request */ - struct iattr * cr_attrs; /* request */ - struct nfs4_change_info * cr_cinfo; /* response */ + const struct qstr * name; + const struct nfs_server * server; + const struct iattr * attrs; + const struct nfs_fh * dir_fh; + const u32 * bitmask; }; + +struct nfs4_create_res { + const struct nfs_server * server; + struct nfs_fh * fh; + struct nfs_fattr * fattr; + struct nfs4_change_info dir_cinfo; +}; + + #define cr_textlen u.symlink.textlen #define cr_text u.symlink.text #define cr_specdata1 u.device.specdata1 @@ -540,10 +547,6 @@ struct nfs4_getattr_res { struct nfs_fattr * fattr; }; -struct nfs4_getfh { - struct nfs_fh * gf_fhandle; /* response */ -}; - struct nfs4_link_arg { const struct nfs_fh * fh; const struct nfs_fh * dir_fh; @@ -647,9 +650,7 @@ struct nfs4_op { u32 opnum; union { struct nfs4_close close; - struct nfs4_create create; struct nfs4_getattr getattr; - struct nfs4_getfh getfh; struct nfs4_open open; struct nfs4_open_confirm open_confirm; struct nfs4_putfh putfh; -- cgit v1.2.3 From f3e5aa184cb8e31a8915d70c9e0a0700e8b9a483 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:35:03 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating PATHCONF RPC calls. --- fs/nfs/nfs4proc.c | 43 ++++++++--------- fs/nfs/nfs4xdr.c | 120 ++++++++++++++++++++++++++++++++++++++++++------ include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 6 ++- 4 files changed, 130 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2693f8bdbec5..682c9c2d1832 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -119,15 +119,13 @@ u32 nfs4_pathconf_bitmap[2] = { static inline void __nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap, struct nfs_fattr *fattr, - struct nfs_fsstat *fsstat, - struct nfs_pathconf *pathconf) + struct nfs_fsstat *fsstat) { struct nfs4_getattr *getattr = GET_OP(cp, getattr); - getattr->gt_bmval = bitmap; - getattr->gt_attrs = fattr; + getattr->gt_bmval = bitmap; + getattr->gt_attrs = fattr; getattr->gt_fsstat = fsstat; - getattr->gt_pathconf = pathconf; OPNUM(cp) = OP_GETATTR; cp->req_nops++; @@ -137,8 +135,7 @@ static void nfs4_setup_getattr(struct nfs4_compound *cp, struct nfs_fattr *fattr) { - __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr, - NULL, NULL); + __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr, NULL); } static void @@ -146,15 +143,7 @@ nfs4_setup_statfs(struct nfs4_compound *cp, struct nfs_fsstat *fsstat) { __nfs4_setup_getattr(cp, nfs4_statfs_bitmap, - NULL, fsstat, NULL); -} - -static void -nfs4_setup_pathconf(struct nfs4_compound *cp, - struct nfs_pathconf *pathconf) -{ - __nfs4_setup_getattr(cp, nfs4_pathconf_bitmap, - NULL, NULL, pathconf); + NULL, fsstat); } static void @@ -1380,17 +1369,21 @@ static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, s return nfs4_map_errors(nfs4_do_fsinfo(server, fhandle, fsinfo)); } -static int -nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_pathconf *pathconf) +static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_pathconf *pathconf) { - struct nfs4_compound compound; - struct nfs4_op ops[2]; + struct nfs4_pathconf_arg args = { + .fh = fhandle, + .bitmask = nfs4_pathconf_bitmap, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], + .rpc_argp = &args, + .rpc_resp = pathconf, + }; - nfs4_setup_compound(&compound, ops, server, "statfs"); - nfs4_setup_putfh(&compound, fhandle); - nfs4_setup_pathconf(&compound, pathconf); - return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); + pathconf->fattr->valid = 0; + return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); } static void diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1ab60b1dbf90..50dbcfb82f34 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -319,6 +319,12 @@ static int nfs_stat_to_errno(int); decode_create_maxsz + \ decode_getattr_maxsz + \ decode_getfh_maxsz) +#define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_getattr_maxsz) @@ -1658,6 +1664,27 @@ nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle) return status; } +/* + * a PATHCONF request + */ +static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) +{ + extern u32 nfs4_pathconf_bitmap[2]; + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if (!status) + status = encode_getattr_one(&xdr, + args->bitmask[0] & nfs4_pathconf_bitmap[0]); + return status; +} + /* * a RENEW request */ @@ -1911,6 +1938,40 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t return 0; } +static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink) +{ + uint32_t *p; + int status = 0; + + *maxlink = 1; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) { + READ_BUF(4); + READ32(*maxlink); + bitmap[0] &= ~FATTR4_WORD0_MAXLINK; + } + dprintk("%s: maxlink=%u\n", __FUNCTION__, *maxlink); + return status; +} + +static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname) +{ + uint32_t *p; + int status = 0; + + *maxname = 1024; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) { + READ_BUF(4); + READ32(*maxname); + bitmap[0] &= ~FATTR4_WORD0_MAXNAME; + } + dprintk("%s: maxname=%u\n", __FUNCTION__, *maxname); + return status; +} + static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode) { uint32_t *p; @@ -2184,7 +2245,6 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) } extern uint32_t nfs4_fsstat_bitmap[2]; -extern uint32_t nfs4_pathconf_bitmap[2]; static int decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, @@ -2192,7 +2252,6 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, { struct nfs_fattr *nfp = getattr->gt_attrs; struct nfs_fsstat *fsstat = getattr->gt_fsstat; - struct nfs_pathconf *pathconf = getattr->gt_pathconf; uint32_t attrlen, dummy32, bmlen, bmval0 = 0, bmval1 = 0, @@ -2294,18 +2353,6 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, READ64(fsstat->tfiles); dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles); } - if (bmval0 & FATTR4_WORD0_MAXLINK) { - READ_BUF(4); - len += 4; - READ32(pathconf->max_link); - dprintk("read_attrs: maxlink=%d\n", pathconf->max_link); - } - if (bmval0 & FATTR4_WORD0_MAXNAME) { - READ_BUF(4); - len += 4; - READ32(pathconf->max_namelen); - dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen); - } if (bmval1 & FATTR4_WORD1_MODE) { READ_BUF(4); @@ -2414,6 +2461,32 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, DECODE_TAIL; } +static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf) +{ + uint32_t *savep; + uint32_t attrlen, + bitmap[2] = {0}; + int status; + + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto xdr_error; + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto xdr_error; + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) + goto xdr_error; + + if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0) + goto xdr_error; + if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0) + goto xdr_error; + + status = verify_attr_len(xdr, savep, attrlen); +xdr_error: + if (status != 0) + printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + return status; +} + static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server) { uint32_t *savep; @@ -3556,6 +3629,24 @@ nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo return status; } +/* + * PATHCONF request + */ +static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (!status) + status = decode_putfh(&xdr); + if (!status) + status = decode_pathconf(&xdr, pathconf); + return status; +} + /* * Decode RENEW response */ @@ -3758,6 +3849,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(RENAME, enc_rename, dec_rename), PROC(LINK, enc_link, dec_link), PROC(CREATE, enc_create, dec_create), + PROC(PATHCONF, enc_pathconf, dec_pathconf), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 6137a19830f0..46bdbb10987a 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -311,6 +311,7 @@ enum { NFSPROC4_CLNT_RENAME, NFSPROC4_CLNT_LINK, NFSPROC4_CLNT_CREATE, + NFSPROC4_CLNT_PATHCONF, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index c423805bc7a0..b7a2c1b1d2ee 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -534,7 +534,6 @@ struct nfs4_getattr { u32 * gt_bmval; /* request */ struct nfs_fattr * gt_attrs; /* response */ struct nfs_fsstat * gt_fsstat; /* response */ - struct nfs_pathconf * gt_pathconf; /* response */ }; struct nfs4_getattr_arg { @@ -590,6 +589,11 @@ struct nfs4_open_confirm { char * oc_stateid; /* request */ }; +struct nfs4_pathconf_arg { + const struct nfs_fh * fh; + const u32 * bitmask; +}; + struct nfs4_putfh { struct nfs_fh * pf_fhandle; /* request */ }; -- cgit v1.2.3 From 33abaafc6b105f09aeda7263b5db06f070eebc9a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:36:11 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating STATFS RPC calls. --- fs/nfs/nfs4proc.c | 35 ++++---- fs/nfs/nfs4xdr.c | 222 +++++++++++++++++++++++++++++++++++++++--------- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 5 ++ 4 files changed, 204 insertions(+), 59 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 682c9c2d1832..34c0e431a371 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -118,14 +118,13 @@ u32 nfs4_pathconf_bitmap[2] = { static inline void __nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap, - struct nfs_fattr *fattr, - struct nfs_fsstat *fsstat) + struct nfs_fattr *fattr) { struct nfs4_getattr *getattr = GET_OP(cp, getattr); getattr->gt_bmval = bitmap; getattr->gt_attrs = fattr; - getattr->gt_fsstat = fsstat; + getattr->gt_fsstat = NULL; OPNUM(cp) = OP_GETATTR; cp->req_nops++; @@ -135,15 +134,7 @@ static void nfs4_setup_getattr(struct nfs4_compound *cp, struct nfs_fattr *fattr) { - __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr, NULL); -} - -static void -nfs4_setup_statfs(struct nfs4_compound *cp, - struct nfs_fsstat *fsstat) -{ - __nfs4_setup_getattr(cp, nfs4_statfs_bitmap, - NULL, fsstat); + __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr); } static void @@ -1338,17 +1329,21 @@ static int nfs4_proc_mknod(struct inode *dir, struct qstr *name, return nfs4_map_errors(status); } -static int -nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, +static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) { - struct nfs4_compound compound; - struct nfs4_op ops[2]; + struct nfs4_statfs_arg args = { + .fh = fhandle, + .bitmask = nfs4_statfs_bitmap, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], + .rpc_argp = &args, + .rpc_resp = fsstat, + }; - nfs4_setup_compound(&compound, ops, server, "statfs"); - nfs4_setup_putfh(&compound, fhandle); - nfs4_setup_statfs(&compound, fsstat); - return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); + fsstat->fattr->valid = 0; + return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); } static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 50dbcfb82f34..cb4bc0c23e7e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -325,6 +325,12 @@ static int nfs_stat_to_errno(int); #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_getattr_maxsz) +#define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 12) @@ -1685,6 +1691,28 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct return status; } +/* + * a STATFS request + */ +static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) +{ + extern u32 nfs4_statfs_bitmap[]; + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if (status == 0) + status = encode_getattr_two(&xdr, + args->bitmask[0] & nfs4_statfs_bitmap[0], + args->bitmask[1] & nfs4_statfs_bitmap[1]); + return status; +} + /* * a RENEW request */ @@ -1938,6 +1966,57 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t return 0; } +static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) { + READ_BUF(8); + READ64(*res); + bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL; + } + dprintk("%s: files avail=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) { + READ_BUF(8); + READ64(*res); + bitmap[0] &= ~FATTR4_WORD0_FILES_FREE; + } + dprintk("%s: files free=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) { + READ_BUF(8); + READ64(*res); + bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL; + } + dprintk("%s: files total=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink) { uint32_t *p; @@ -2075,6 +2154,57 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde return 0; } +static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) { + READ_BUF(8); + READ64(*res); + bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL; + } + dprintk("%s: space avail=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) { + READ_BUF(8); + READ64(*res); + bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE; + } + dprintk("%s: space free=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + +static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U))) + return -EIO; + if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) { + READ_BUF(8); + READ64(*res); + bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL; + } + dprintk("%s: space total=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used) { uint32_t *p; @@ -2244,14 +2374,11 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) return 0; } -extern uint32_t nfs4_fsstat_bitmap[2]; - static int decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, struct nfs_server *server) { struct nfs_fattr *nfp = getattr->gt_attrs; - struct nfs_fsstat *fsstat = getattr->gt_fsstat; uint32_t attrlen, dummy32, bmlen, bmval0 = 0, bmval1 = 0, @@ -2335,24 +2462,6 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, READ64(nfp->fileid); dprintk("read_attrs: fileid=%Ld\n", (long long) nfp->fileid); } - if (bmval0 & FATTR4_WORD0_FILES_AVAIL) { - READ_BUF(8); - len += 8; - READ64(fsstat->afiles); - dprintk("read_attrs: files_avail=0x%Lx\n", (long long) fsstat->afiles); - } - if (bmval0 & FATTR4_WORD0_FILES_FREE) { - READ_BUF(8); - len += 8; - READ64(fsstat->ffiles); - dprintk("read_attrs: files_free=0x%Lx\n", (long long) fsstat->ffiles); - } - if (bmval0 & FATTR4_WORD0_FILES_TOTAL) { - READ_BUF(8); - len += 8; - READ64(fsstat->tfiles); - dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles); - } if (bmval1 & FATTR4_WORD1_MODE) { READ_BUF(4); @@ -2413,24 +2522,6 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, nfp->rdev = 0; dprintk("read_attrs: rdev=%u:%u\n", major, minor); } - if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) { - READ_BUF(8); - len += 8; - READ64(fsstat->abytes); - dprintk("read_attrs: savail=0x%Lx\n", (long long) fsstat->abytes); - } - if (bmval1 & FATTR4_WORD1_SPACE_FREE) { - READ_BUF(8); - len += 8; - READ64(fsstat->fbytes); - dprintk("read_attrs: sfree=0x%Lx\n", (long long) fsstat->fbytes); - } - if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) { - READ_BUF(8); - len += 8; - READ64(fsstat->tbytes); - dprintk("read_attrs: stotal=0x%Lx\n", (long long) fsstat->tbytes); - } if (bmval1 & FATTR4_WORD1_SPACE_USED) { READ_BUF(8); len += 8; @@ -2461,6 +2552,40 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, DECODE_TAIL; } +static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) +{ + uint32_t *savep; + uint32_t attrlen, + bitmap[2] = {0}; + int status; + + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto xdr_error; + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto xdr_error; + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) + goto xdr_error; + + if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0) + goto xdr_error; + if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0) + goto xdr_error; + if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0) + goto xdr_error; + if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0) + goto xdr_error; + if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0) + goto xdr_error; + if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0) + goto xdr_error; + + status = verify_attr_len(xdr, savep, attrlen); +xdr_error: + if (status != 0) + printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + return status; +} + static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf) { uint32_t *savep; @@ -3647,6 +3772,24 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_p return status; } +/* + * STATFS request + */ +static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (!status) + status = decode_putfh(&xdr); + if (!status) + status = decode_statfs(&xdr, fsstat); + return status; +} + /* * Decode RENEW response */ @@ -3850,6 +3993,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(LINK, enc_link, dec_link), PROC(CREATE, enc_create, dec_create), PROC(PATHCONF, enc_pathconf, dec_pathconf), + PROC(STATFS, enc_statfs, dec_statfs), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 46bdbb10987a..b02f2e261c97 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -312,6 +312,7 @@ enum { NFSPROC4_CLNT_LINK, NFSPROC4_CLNT_CREATE, NFSPROC4_CLNT_PATHCONF, + NFSPROC4_CLNT_STATFS, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index b7a2c1b1d2ee..1e3ce614b166 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -650,6 +650,11 @@ struct nfs4_setclientid { struct nfs4_client * sc_state; /* response */ }; +struct nfs4_statfs_arg { + const struct nfs_fh * fh; + const u32 * bitmask; +}; + struct nfs4_op { u32 opnum; union { -- cgit v1.2.3 From 15c5fef529e2a875bb2af3af13744feea6d6586c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:36:57 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme when doing sillyrename() completion. --- fs/nfs/nfs4proc.c | 71 +++++++++++-------------------------------------- fs/nfs/nfs4xdr.c | 12 --------- include/linux/nfs_xdr.h | 7 ----- 3 files changed, 15 insertions(+), 75 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 34c0e431a371..eaead6f1a1e0 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -116,27 +116,6 @@ u32 nfs4_pathconf_bitmap[2] = { 0 }; -static inline void -__nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap, - struct nfs_fattr *fattr) -{ - struct nfs4_getattr *getattr = GET_OP(cp, getattr); - - getattr->gt_bmval = bitmap; - getattr->gt_attrs = fattr; - getattr->gt_fsstat = NULL; - - OPNUM(cp) = OP_GETATTR; - cp->req_nops++; -} - -static void -nfs4_setup_getattr(struct nfs4_compound *cp, - struct nfs_fattr *fattr) -{ - __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr); -} - static void nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) { @@ -220,18 +199,6 @@ nfs4_setup_readlink(struct nfs4_compound *cp, int count, struct page **pages) cp->req_nops++; } -static void -nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_change_info *cinfo) -{ - struct nfs4_remove *remove = GET_OP(cp, remove); - - remove->name = name; - remove->rm_cinfo = cinfo; - - OPNUM(cp) = OP_REMOVE; - cp->req_nops++; -} - static void renew_lease(struct nfs_server *server, unsigned long timestamp) { @@ -1100,46 +1067,38 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name) } struct unlink_desc { - struct nfs4_compound compound; - struct nfs4_op ops[3]; - struct nfs4_change_info cinfo; - struct nfs_fattr attrs; + struct nfs4_remove_arg args; + struct nfs4_change_info res; }; -static int -nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) +static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, + struct qstr *name) { - struct unlink_desc * up; - struct nfs4_compound * cp; + struct unlink_desc *up; up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL); if (!up) return -ENOMEM; - cp = &up->compound; - nfs4_setup_compound(cp, up->ops, NFS_SERVER(dir->d_inode), "unlink_setup"); - nfs4_setup_putfh(cp, NFS_FH(dir->d_inode)); - nfs4_setup_remove(cp, name, &up->cinfo); - nfs4_setup_getattr(cp, &up->attrs); + up->args.fh = NFS_FH(dir->d_inode); + up->args.name = name; - msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND]; - msg->rpc_argp = cp; - msg->rpc_resp = cp; + 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 dentry *dir, struct rpc_task *task) { struct rpc_message *msg = &task->tk_msg; struct unlink_desc *up; - if (msg->rpc_argp) { - up = (struct unlink_desc *) msg->rpc_argp; - process_lease(&up->compound); - process_cinfo(&up->cinfo, &up->attrs); - nfs_refresh_inode(dir->d_inode, &up->attrs); + if (msg->rpc_resp != NULL) { + up = container_of(msg->rpc_resp, struct unlink_desc, res); + update_changeattr(dir->d_inode, &up->res); kfree(up); + msg->rpc_resp = NULL; msg->rpc_argp = NULL; } return 0; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index cb4bc0c23e7e..bc4715c13f21 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1138,9 +1138,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs for (i = 0; i < cp->req_nops; i++) { switch (cp->ops[i].opnum) { - case OP_GETATTR: - status = encode_getattr(xdr, &cp->ops[i].u.getattr); - break; case OP_PUTFH: status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle); break; @@ -1150,9 +1147,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_READLINK: status = encode_readlink(xdr, &cp->ops[i].u.readlink, req); break; - case OP_REMOVE: - status = encode_remove(xdr, cp->ops[i].u.remove.name); - break; default: BUG(); } @@ -3220,9 +3214,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs op = &cp->ops[0]; for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++, op++) { switch (op->opnum) { - case OP_GETATTR: - status = decode_getattr(xdr, &op->u.getattr, cp->server); - break; case OP_PUTFH: status = decode_putfh(xdr); break; @@ -3232,9 +3223,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_READLINK: status = decode_readlink(xdr, req, &op->u.readlink); break; - case OP_REMOVE: - status = decode_remove(xdr, op->u.remove.rm_cinfo); - break; default: BUG(); return -EIO; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 1e3ce614b166..81faecbaa2fc 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -613,11 +613,6 @@ struct nfs4_readlink { struct page ** rl_pages; /* zero-copy data */ }; -struct nfs4_remove { - struct qstr * name; /* request */ - struct nfs4_change_info * rm_cinfo; /* response */ -}; - struct nfs4_remove_arg { const struct nfs_fh * fh; const struct qstr * name; @@ -659,13 +654,11 @@ struct nfs4_op { u32 opnum; union { struct nfs4_close close; - struct nfs4_getattr getattr; struct nfs4_open open; struct nfs4_open_confirm open_confirm; struct nfs4_putfh putfh; struct nfs4_readdir readdir; struct nfs4_readlink readlink; - struct nfs4_remove remove; struct nfs4_client * renew; struct nfs4_setattr setattr; } u; -- cgit v1.2.3 From 1513be7e1eead93049ea2481fb6ebeaa4ca5df51 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:37:43 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating READLINK RPC calls. --- fs/nfs/nfs4proc.c | 32 ++++++++++--------------- fs/nfs/nfs4xdr.c | 63 ++++++++++++++++++++++++++++++++++++++++--------- include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 5 ++-- 4 files changed, 68 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index eaead6f1a1e0..22c0c852cde0 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -187,18 +187,6 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, kunmap_atomic(start, KM_USER0); } -static void -nfs4_setup_readlink(struct nfs4_compound *cp, int count, struct page **pages) -{ - struct nfs4_readlink *readlink = GET_OP(cp, readlink); - - readlink->rl_count = count; - readlink->rl_pages = pages; - - OPNUM(cp) = OP_READLINK; - cp->req_nops++; -} - static void renew_lease(struct nfs_server *server, unsigned long timestamp) { @@ -885,16 +873,20 @@ static int nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode * Both of these changes to the XDR layer would in fact be quite * minor, but I decided to leave them for a subsequent patch. */ -static int -nfs4_proc_readlink(struct inode *inode, struct page *page) +static int nfs4_proc_readlink(struct inode *inode, struct page *page) { - struct nfs4_compound compound; - struct nfs4_op ops[2]; + struct nfs4_readlink args = { + .fh = NFS_FH(inode), + .count = PAGE_CACHE_SIZE, + .pages = &page, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], + .rpc_argp = &args, + .rpc_resp = NULL, + }; - nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "readlink"); - nfs4_setup_putfh(&compound, NFS_FH(inode)); - nfs4_setup_readlink(&compound, PAGE_CACHE_SIZE, &page); - return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); + return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0)); } static int diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index bc4715c13f21..5994a31d1d7d 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -132,6 +132,12 @@ static int nfs_stat_to_errno(int); #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ op_decode_hdr_maxsz + 2) +#define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz) +#define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz) #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ op_encode_hdr_maxsz + 8) @@ -963,8 +969,7 @@ encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir *readdir, struct rpc_ return 0; } -static int -encode_readlink(struct xdr_stream *xdr, struct nfs4_readlink *readlink, struct rpc_rqst *req) +static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req) { struct rpc_auth *auth = req->rq_task->tk_auth; int replen; @@ -978,7 +983,7 @@ encode_readlink(struct xdr_stream *xdr, struct nfs4_readlink *readlink, struct r * + OP_READLINK + status = 7 */ replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; - xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count); + xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, readlink->count); return 0; } @@ -1144,9 +1149,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_READDIR: status = encode_readdir(xdr, &cp->ops[i].u.readdir, req); break; - case OP_READLINK: - status = encode_readlink(xdr, &cp->ops[i].u.readlink, req); - break; default: BUG(); } @@ -1541,6 +1543,27 @@ out: return status; } +/* + * Encode a READLINK request + */ +static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_readlink(&xdr, args, req); +out: + return status; +} + /* * Encode a READ request */ @@ -3018,8 +3041,7 @@ err_unmap: return -errno_NFSERR_IO; } -static int -decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readlink *readlink) +static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct iovec *iov = rcvbuf->head; @@ -3220,9 +3242,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_READDIR: status = decode_readdir(xdr, req, &op->u.readdir); break; - case OP_READLINK: - status = decode_readlink(xdr, req, &op->u.readlink); - break; default: BUG(); return -EIO; @@ -3651,6 +3670,27 @@ out: return status; } +/* + * Decode READLINK response + */ +static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_readlink(&xdr, rqstp); +out: + return status; +} + /* * Decode Read response */ @@ -3982,6 +4022,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(CREATE, enc_create, dec_create), PROC(PATHCONF, enc_pathconf, dec_pathconf), PROC(STATFS, enc_statfs, dec_statfs), + PROC(READLINK, enc_readlink, dec_readlink), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index b02f2e261c97..51a04a014ff2 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -313,6 +313,7 @@ enum { NFSPROC4_CLNT_CREATE, NFSPROC4_CLNT_PATHCONF, NFSPROC4_CLNT_STATFS, + NFSPROC4_CLNT_READLINK, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 81faecbaa2fc..4883b7ca3a83 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -609,8 +609,9 @@ struct nfs4_readdir { }; struct nfs4_readlink { - u32 rl_count; /* zero-copy data */ - struct page ** rl_pages; /* zero-copy data */ + const struct nfs_fh * fh; + u32 count; /* zero-copy data */ + struct page ** pages; /* zero-copy data */ }; struct nfs4_remove_arg { -- cgit v1.2.3 From 829186b78226c75821d8955c63dcb45966313058 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:38:51 -0700 Subject: NFSv4: use the (more efficient) NFSv2/v3-like XDR scheme for generating READDIR RPC calls. --- fs/nfs/nfs4proc.c | 132 +++++++++------------------------ fs/nfs/nfs4xdr.c | 192 ++++++++++++++++-------------------------------- include/linux/nfs4.h | 2 +- include/linux/nfs_xdr.h | 97 +++--------------------- 4 files changed, 108 insertions(+), 315 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 22c0c852cde0..6df2b006d077 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -51,9 +51,6 @@ #define NFS4_POLL_RETRY_TIME (15*HZ) -#define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name -#define OPNUM(cp) cp->ops[cp->req_nops].opnum - static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); @@ -72,15 +69,6 @@ static inline int nfs4_map_errors(int err) return err; } -static void -nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops, - struct nfs_server *server, char *tag) -{ - memset(cp, 0, sizeof(*cp)); - cp->ops = ops; - cp->server = server; -} - /* * This is our standard bitmap for GETATTR requests. */ @@ -116,37 +104,21 @@ u32 nfs4_pathconf_bitmap[2] = { 0 }; -static void -nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle) -{ - struct nfs4_putfh *putfh = GET_OP(cp, putfh); - - putfh->pf_fhandle = fhandle; - - OPNUM(cp) = OP_PUTFH; - cp->req_nops++; -} - -static void -nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, - struct page **pages, unsigned int bufsize, struct dentry *dentry) +static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, + struct nfs4_readdir_arg *readdir) { u32 *start, *p; - struct nfs4_readdir *readdir = GET_OP(cp, readdir); - - BUG_ON(bufsize < 80); - readdir->rd_cookie = (cookie > 2) ? cookie : 0; - memcpy(&readdir->rd_req_verifier, verifier, sizeof(readdir->rd_req_verifier)); - readdir->rd_count = bufsize; - readdir->rd_bmval[0] = FATTR4_WORD0_FILEID; - readdir->rd_bmval[1] = 0; - readdir->rd_pages = pages; - readdir->rd_pgbase = 0; - - OPNUM(cp) = OP_READDIR; - cp->req_nops++; - if (cookie >= 2) + BUG_ON(readdir->count < 80); + if (cookie > 2) { + readdir->cookie = (cookie > 2) ? cookie : 0; + memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); + return; + } + + readdir->cookie = 0; + memset(&readdir->verifier, 0, sizeof(readdir->verifier)); + if (cookie == 2) return; /* @@ -156,7 +128,7 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, * when talking to the server, we always send cookie 0 * instead of 1 or 2. */ - start = p = (u32 *)kmap_atomic(*pages, KM_USER0); + start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0); if (cookie == 0) { *p++ = xdr_one; /* next */ @@ -168,7 +140,7 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, *p++ = xdr_one; /* bitmap length */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(8); /* attribute buffer length */ - p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode)); + p = xdr_encode_hyper(p, dentry->d_inode->i_ino); } *p++ = xdr_one; /* next */ @@ -180,10 +152,10 @@ nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, *p++ = xdr_one; /* bitmap length */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(8); /* attribute buffer length */ - p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode)); + p = xdr_encode_hyper(p, dentry->d_parent->d_inode->i_ino); - readdir->rd_pgbase = (char *)p - (char *)start; - readdir->rd_count -= readdir->rd_pgbase; + readdir->pgbase = (char *)p - (char *)start; + readdir->count -= readdir->pgbase; kunmap_atomic(start, KM_USER0); } @@ -197,47 +169,6 @@ renew_lease(struct nfs_server *server, unsigned long timestamp) spin_unlock(&clp->cl_lock); } -static inline void -process_lease(struct nfs4_compound *cp) -{ - /* - * Generic lease processing: If this operation contains a - * lease-renewing operation, and it succeeded, update the RENEW time - * in the superblock. Instead of the current time, we use the time - * when the request was sent out. (All we know is that the lease was - * renewed sometime between then and now, and we have to assume the - * worst case.) - * - * Notes: - * (1) renewd doesn't acquire the spinlock when messing with - * server->last_renewal; this is OK since rpciod always runs - * under the BKL. - * (2) cp->timestamp was set at the end of XDR encode. - */ - if (!cp->renew_index) - return; - if (!cp->toplevel_status || cp->resp_nops > cp->renew_index) - renew_lease(cp->server, cp->timestamp); -} - -static int -nfs4_call_compound(struct nfs4_compound *cp, struct rpc_cred *cred, int flags) -{ - int status; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND], - .rpc_argp = cp, - .rpc_resp = cp, - .rpc_cred = cred, - }; - - status = rpc_call_sync(cp->server->client, &msg, flags); - if (!status) - process_lease(cp); - - return status; -} - static inline void process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr) { @@ -1209,24 +1140,31 @@ static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name, return nfs4_map_errors(status); } -static int -nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, +static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page *page, unsigned int count, int plus) { struct inode *dir = dentry->d_inode; - struct nfs4_compound compound; - struct nfs4_op ops[2]; + struct nfs4_readdir_arg args = { + .fh = NFS_FH(dir), + .pages = &page, + .pgbase = 0, + .count = count, + }; + struct nfs4_readdir_res res; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR], + .rpc_argp = &args, + .rpc_resp = &res, + .rpc_cred = cred, + }; int status; lock_kernel(); - - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "readdir"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_readdir(&compound, cookie, NFS_COOKIEVERF(dir), &page, count, dentry); - status = nfs4_call_compound(&compound, cred, 0); + nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); + res.pgbase = args.pgbase; + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (status == 0) - memcpy(NFS_COOKIEVERF(dir), ops[1].u.readdir.rd_resp_verifier.data, NFS4_VERIFIER_SIZE); - + memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); unlock_kernel(); return nfs4_map_errors(status); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5994a31d1d7d..6f48289090f4 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -138,6 +138,12 @@ static int nfs_stat_to_errno(int); #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ op_decode_hdr_maxsz) +#define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz + 9) +#define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 2) #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ op_encode_hdr_maxsz + 8) @@ -941,8 +947,7 @@ encode_read(struct xdr_stream *xdr, struct nfs_readargs *args) return 0; } -static int -encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir *readdir, struct rpc_rqst *req) +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; int replen; @@ -950,21 +955,21 @@ encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir *readdir, struct rpc_ RESERVE_SPACE(32+sizeof(nfs4_verifier)); WRITE32(OP_READDIR); - WRITE64(readdir->rd_cookie); - WRITEMEM(readdir->rd_req_verifier.data, sizeof(readdir->rd_req_verifier.data)); - WRITE32(readdir->rd_count >> 5); /* meaningless "dircount" field */ - WRITE32(readdir->rd_count); + WRITE64(readdir->cookie); + WRITEMEM(readdir->verifier.data, sizeof(readdir->verifier.data)); + WRITE32(readdir->count >> 5); /* meaningless "dircount" field */ + WRITE32(readdir->count); WRITE32(2); - WRITE32(readdir->rd_bmval[0]); - WRITE32(readdir->rd_bmval[1]); + WRITE32(FATTR4_WORD0_FILEID); + WRITE32(0); /* set up reply iovec * 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->rd_pages, - readdir->rd_pgbase, readdir->rd_count); + xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, + readdir->pgbase, readdir->count); return 0; } @@ -1127,56 +1132,10 @@ encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args) return 0; } - -/* FIXME: this sucks */ -static int -encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req) -{ - struct compound_hdr hdr = { - .taglen = cp->taglen, - .tag = cp->tag, - .nops = cp->req_nops, - }; - int i, status = 0; - - encode_compound_hdr(xdr, &hdr); - - for (i = 0; i < cp->req_nops; i++) { - switch (cp->ops[i].opnum) { - case OP_PUTFH: - status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle); - break; - case OP_READDIR: - status = encode_readdir(xdr, &cp->ops[i].u.readdir, req); - break; - default: - BUG(); - } - if (status) - return status; - } - - return 0; -} /* * END OF "GENERIC" ENCODE ROUTINES. */ -/* - * Encode COMPOUND argument - */ -static int -nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *cp) -{ - struct xdr_stream xdr; - int status; - - xdr_init_encode(&xdr, &req->rq_snd_buf, p); - status = encode_compound(&xdr, cp, req); - cp->timestamp = jiffies; - return status; -} - /* * Encode an ACCESS request */ @@ -1564,6 +1523,27 @@ out: return status; } +/* + * Encode a READDIR request + */ +static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_readdir(&xdr, args, req); +out: + return status; +} + /* * Encode a READ request */ @@ -2956,8 +2936,7 @@ decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *re return 0; } -static int -decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir *readdir) +static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct page *page = *rcvbuf->pages; @@ -2971,7 +2950,7 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir if (status) return status; READ_BUF(8); - COPYMEM(readdir->rd_resp_verifier.data, 8); + COPYMEM(readdir->verifier.data, 8); hdrlen = (char *) p - (char *) iov->iov_base; recvd = req->rq_received - hdrlen; @@ -2979,9 +2958,9 @@ decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir pglen = recvd; xdr_read_pages(xdr, pglen); - BUG_ON(pglen + readdir->rd_pgbase > PAGE_CACHE_SIZE); + BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE); kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0); - end = (uint32_t *) ((char *)p + pglen + readdir->rd_pgbase); + end = (uint32_t *) ((char *)p + pglen + readdir->pgbase); entry = p; for (nr = 0; *p++; nr++) { if (p + 3 > end) @@ -3206,53 +3185,6 @@ decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) return 0; } -/* FIXME: this sucks */ -static int -decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req) -{ - struct compound_hdr hdr; - struct nfs4_op *op; - int status; - - status = decode_compound_hdr(xdr, &hdr); - if (status) - goto out; - - cp->toplevel_status = hdr.status; - - /* - * We need this if our zero-copy I/O is going to work. Rumor has - * it that the spec will soon mandate it... - */ - if (hdr.taglen != cp->taglen) - dprintk("nfs4: non-conforming server returns tag length mismatch!\n"); - - cp->resp_nops = hdr.nops; - if (hdr.nops > cp->req_nops) { - dprintk("nfs4: resp_nops > req_nops!\n"); - goto xdr_error; - } - - op = &cp->ops[0]; - for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++, op++) { - switch (op->opnum) { - case OP_PUTFH: - status = decode_putfh(xdr); - break; - case OP_READDIR: - status = decode_readdir(xdr, req, &op->u.readdir); - break; - default: - BUG(); - return -EIO; - } - if (status) - break; - } - - DECODE_TAIL; -} - /* * Decode OPEN_DOWNGRADE response */ @@ -3279,27 +3211,6 @@ out: * END OF "GENERIC" DECODE ROUTINES. */ -/* - * Decode COMPOUND response - */ -static int -nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_compound *cp) -{ - struct xdr_stream xdr; - int status; - - xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); - if ((status = decode_compound(&xdr, cp, rqstp))) - goto out; - - status = 0; - if (cp->toplevel_status) - status = -nfs_stat_to_errno(cp->toplevel_status); - -out: - return status; -} - /* * Decode ACCESS response */ @@ -3691,6 +3602,27 @@ out: return status; } +/* + * Decode READDIR response + */ +static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_readdir(&xdr, rqstp, res); +out: + return status; +} + /* * Decode Read response */ @@ -3995,7 +3927,6 @@ nfs_stat_to_errno(int stat) } struct rpc_procinfo nfs4_procedures[] = { - PROC(COMPOUND, enc_compound, dec_compound), PROC(READ, enc_read, dec_read), PROC(WRITE, enc_write, dec_write), PROC(COMMIT, enc_commit, dec_commit), @@ -4023,6 +3954,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(PATHCONF, enc_pathconf, dec_pathconf), PROC(STATFS, enc_statfs, dec_statfs), PROC(READLINK, enc_readlink, dec_readlink), + PROC(READDIR, enc_readdir, dec_readdir), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 51a04a014ff2..1befa051b63a 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -286,7 +286,6 @@ enum lock_type4 { enum { NFSPROC4_CLNT_NULL = 0, /* Unused */ - NFSPROC4_CLNT_COMPOUND, /* Soon to be unused */ NFSPROC4_CLNT_READ, NFSPROC4_CLNT_WRITE, NFSPROC4_CLNT_COMMIT, @@ -314,6 +313,7 @@ enum { NFSPROC4_CLNT_PATHCONF, NFSPROC4_CLNT_STATFS, NFSPROC4_CLNT_READLINK, + NFSPROC4_CLNT_READDIR, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 4883b7ca3a83..c77d4205959b 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -496,11 +496,6 @@ struct nfs4_accessres { u32 access; }; -struct nfs4_close { - char * cl_stateid; /* request */ - u32 cl_seqid; /* request */ -}; - struct nfs4_create_arg { u32 ftype; union { @@ -524,12 +519,6 @@ struct nfs4_create_res { struct nfs4_change_info dir_cinfo; }; - -#define cr_textlen u.symlink.textlen -#define cr_text u.symlink.text -#define cr_specdata1 u.device.specdata1 -#define cr_specdata2 u.device.specdata2 - struct nfs4_getattr { u32 * gt_bmval; /* request */ struct nfs_fattr * gt_attrs; /* response */ @@ -568,44 +557,23 @@ struct nfs4_lookup_root_arg { const u32 * bitmask; }; -struct nfs4_open { - struct nfs4_client * op_client_state; /* request */ - u32 op_share_access; /* request */ - u32 op_opentype; /* request */ - u32 op_createmode; /* request */ - union { /* request */ - struct iattr * attrs; /* UNCHECKED, GUARDED */ - nfs4_verifier verifier; /* EXCLUSIVE */ - } u; - struct qstr * op_name; /* request */ - char * op_stateid; /* response */ - struct nfs4_change_info * op_cinfo; /* response */ - u32 * op_rflags; /* response */ -}; -#define op_attrs u.attrs -#define op_verifier u.verifier - -struct nfs4_open_confirm { - char * oc_stateid; /* request */ -}; - struct nfs4_pathconf_arg { const struct nfs_fh * fh; const u32 * bitmask; }; -struct nfs4_putfh { - struct nfs_fh * pf_fhandle; /* request */ +struct nfs4_readdir_arg { + const struct nfs_fh * fh; + u64 cookie; + nfs4_verifier verifier; + u32 count; + struct page ** pages; /* zero-copy data */ + unsigned int pgbase; /* zero-copy data */ }; -struct nfs4_readdir { - u64 rd_cookie; /* request */ - nfs4_verifier rd_req_verifier; /* request */ - u32 rd_count; /* request */ - u32 rd_bmval[2]; /* request */ - nfs4_verifier rd_resp_verifier; /* response */ - struct page ** rd_pages; /* zero-copy data */ - unsigned int rd_pgbase; /* zero-copy data */ +struct nfs4_readdir_res { + nfs4_verifier verifier; + unsigned int pgbase; }; struct nfs4_readlink { @@ -631,11 +599,6 @@ struct nfs4_rename_res { struct nfs4_change_info new_cinfo; }; -struct nfs4_setattr { - char * st_stateid; /* request */ - struct iattr * st_iap; /* request */ -}; - struct nfs4_setclientid { nfs4_verifier sc_verifier; /* request */ char * sc_name; /* request */ @@ -651,46 +614,6 @@ struct nfs4_statfs_arg { const u32 * bitmask; }; -struct nfs4_op { - u32 opnum; - union { - struct nfs4_close close; - struct nfs4_open open; - struct nfs4_open_confirm open_confirm; - struct nfs4_putfh putfh; - struct nfs4_readdir readdir; - struct nfs4_readlink readlink; - struct nfs4_client * renew; - struct nfs4_setattr setattr; - } u; -}; - -struct nfs4_compound { - unsigned int flags; /* defined below */ - struct nfs_server * server; - - /* RENEW information */ - int renew_index; - unsigned long timestamp; - - /* scratch variables for XDR encode/decode */ - int nops; - u32 * p; - u32 * end; - - /* the individual COMPOUND operations */ - struct nfs4_op *ops; - - /* request */ - int req_nops; - u32 taglen; - char * tag; - - /* response */ - int resp_nops; - int toplevel_status; -}; - #endif /* CONFIG_NFS_V4 */ struct nfs_page; -- cgit v1.2.3 From ea6cacaf00b9e7fa2a32ac46a25e72d0214fcc9c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:39:33 -0700 Subject: NFSv4: assorted code readability cleanups in the XDR --- fs/nfs/nfs4proc.c | 54 +----- fs/nfs/nfs4xdr.c | 505 +++++++++--------------------------------------- include/linux/nfs_xdr.h | 44 ++--- 3 files changed, 117 insertions(+), 486 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6df2b006d077..c3e1046cd445 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -169,19 +169,6 @@ renew_lease(struct nfs_server *server, unsigned long timestamp) spin_unlock(&clp->cl_lock); } -static inline void -process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr) -{ - BUG_ON((fattr->valid & NFS_ATTR_FATTR) == 0); - BUG_ON((fattr->valid & NFS_ATTR_FATTR_V4) == 0); - - if (fattr->change_attr == info->after) { - fattr->pre_change_attr = info->before; - fattr->valid |= NFS_ATTR_PRE_CHANGE; - fattr->timestamp = jiffies; - } -} - static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinfo) { struct nfs_inode *nfsi = NFS_I(inode); @@ -203,12 +190,6 @@ nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) struct nfs_fattr fattr = { .valid = 0, }; - struct nfs4_change_info d_cinfo; - struct nfs4_getattr f_getattr = { - .gt_bmval = nfs4_fattr_bitmap, - .gt_attrs = &fattr, - }; - struct nfs_open_reclaimargs o_arg = { .fh = NFS_FH(inode), .seqid = sp->so_seqid, @@ -216,11 +197,10 @@ nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) .share_access = state->state, .clientid = server->nfs4_state->cl_clientid, .claim = NFS4_OPEN_CLAIM_PREVIOUS, - .f_getattr = &f_getattr, + .bitmask = nfs4_fattr_bitmap, }; struct nfs_openres o_res = { - .cinfo = &d_cinfo, - .f_getattr = &f_getattr, + .f_attr = &fattr, .server = server, /* Grrr */ }; struct rpc_message msg = { @@ -250,36 +230,21 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt struct nfs4_state *state = NULL; struct nfs_server *server = NFS_SERVER(dir); struct inode *inode = NULL; - struct nfs4_change_info d_cinfo; int status; - struct nfs_fattr d_attr = { - .valid = 0, - }; struct nfs_fattr f_attr = { .valid = 0, }; - struct nfs4_getattr f_getattr = { - .gt_bmval = nfs4_fattr_bitmap, - .gt_attrs = &f_attr, - }; - struct nfs4_getattr d_getattr = { - .gt_bmval = nfs4_fattr_bitmap, - .gt_attrs = &d_attr, - }; struct nfs_openargs o_arg = { .fh = NFS_FH(dir), .share_access = flags & (FMODE_READ|FMODE_WRITE), .opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE, .createmode = (flags & O_EXCL) ? NFS4_CREATE_EXCLUSIVE : NFS4_CREATE_UNCHECKED, .name = name, - .f_getattr = &f_getattr, - .d_getattr = &d_getattr, .server = server, + .bitmask = nfs4_fattr_bitmap, }; struct nfs_openres o_res = { - .cinfo = &d_cinfo, - .f_getattr = &f_getattr, - .d_getattr = &d_getattr, + .f_attr = &f_attr, .server = server, }; struct rpc_message msg = { @@ -312,8 +277,7 @@ retry: nfs4_increment_seqid(status, sp); if (status) goto out_up; - process_cinfo(&d_cinfo, &d_attr); - nfs_refresh_inode(dir, &d_attr); + update_changeattr(dir, &o_res.cinfo); status = -ENOMEM; inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr); @@ -395,18 +359,14 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, struct nfs_fh *fhandle, struct iattr *sattr, struct nfs4_state *state) { - struct nfs4_getattr getattr = { - .gt_bmval = nfs4_fattr_bitmap, - .gt_attrs = fattr, - }; struct nfs_setattrargs arg = { .fh = fhandle, .iap = sattr, - .attr = &getattr, .server = server, + .bitmask = nfs4_fattr_bitmap, }; struct nfs_setattrres res = { - .attr = &getattr, + .fattr = fattr, .server = server, }; struct rpc_message msg = { diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 6f48289090f4..ff24d28fc6f3 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -89,8 +89,6 @@ static int nfs_stat_to_errno(int); nfs4_fattr_bitmap_maxsz) #define encode_savefh_maxsz (op_encode_hdr_maxsz) #define decode_savefh_maxsz (op_decode_hdr_maxsz) -#define encode_restorefh_maxsz (op_encode_hdr_maxsz) -#define decode_restorefh_maxsz (op_decode_hdr_maxsz) #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) @@ -158,21 +156,15 @@ static int nfs_stat_to_errno(int); op_decode_hdr_maxsz + 2) #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_savefh_maxsz + \ op_encode_hdr_maxsz + \ 13 + 3 + 2 + 64 + \ encode_getattr_maxsz + \ - encode_getfh_maxsz + \ - encode_restorefh_maxsz + \ - encode_getattr_maxsz) + encode_getfh_maxsz) #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_savefh_maxsz + \ op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \ decode_getattr_maxsz + \ - decode_getfh_maxsz + \ - decode_restorefh_maxsz + \ - decode_getattr_maxsz) + decode_getfh_maxsz) #define NFS4_enc_open_confirm_sz \ (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ @@ -344,8 +336,6 @@ static int nfs_stat_to_errno(int); decode_putfh_maxsz + \ op_decode_hdr_maxsz + 12) - - static struct { unsigned int mode; unsigned int nfs2type; @@ -394,8 +384,7 @@ struct compound_hdr { BUG_ON(!p); \ } while (0) -static int -encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) +static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { uint32_t *p; @@ -547,8 +536,7 @@ static int encode_access(struct xdr_stream *xdr, u32 access) return 0; } -static int -encode_close(struct xdr_stream *xdr, struct nfs_closeargs *arg) +static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) { uint32_t *p; @@ -560,8 +548,7 @@ encode_close(struct xdr_stream *xdr, struct nfs_closeargs *arg) return 0; } -static int -encode_commit(struct xdr_stream *xdr, struct nfs_writeargs *args) +static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args) { uint32_t *p; @@ -605,8 +592,7 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c return encode_attrs(xdr, create->attrs, create->server); } -static int -encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap) +static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap) { uint32_t *p; @@ -617,8 +603,7 @@ encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap) return 0; } -static int -encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1) +static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1) { uint32_t *p; @@ -639,15 +624,7 @@ static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) bitmask[1] & nfs4_fattr_bitmap[1]); } -static inline int -encode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr) -{ - return encode_getattr_two(xdr, getattr->gt_bmval[0], - getattr->gt_bmval[1]); -} - -static int -encode_fsinfo(struct xdr_stream *xdr) +static int encode_fsinfo(struct xdr_stream *xdr) { return encode_getattr_one(xdr, FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXREAD @@ -655,8 +632,7 @@ encode_fsinfo(struct xdr_stream *xdr) | FATTR4_WORD0_LEASE_TIME); } -static int -encode_getfh(struct xdr_stream *xdr) +static int encode_getfh(struct xdr_stream *xdr) { uint32_t *p; @@ -682,8 +658,7 @@ static int encode_link(struct xdr_stream *xdr, const struct qstr *name) * opcode,type,reclaim,offset,length,new_lock_owner = 32 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 */ -static int -encode_lock(struct xdr_stream *xdr, struct nfs_lockargs *arg) +static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg) { uint32_t *p; struct nfs_lock_opargs *opargs = arg->u.lock; @@ -717,8 +692,7 @@ encode_lock(struct xdr_stream *xdr, struct nfs_lockargs *arg) return 0; } -static int -encode_lockt(struct xdr_stream *xdr, struct nfs_lockargs *arg) +static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockargs *arg) { uint32_t *p; struct nfs_lowner *opargs = arg->u.lockt; @@ -735,8 +709,7 @@ encode_lockt(struct xdr_stream *xdr, struct nfs_lockargs *arg) return 0; } -static int -encode_locku(struct xdr_stream *xdr, struct nfs_lockargs *arg) +static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg) { uint32_t *p; struct nfs_locku_opargs *opargs = arg->u.locku; @@ -765,8 +738,7 @@ static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name) return 0; } -static int -encode_open(struct xdr_stream *xdr, struct nfs_openargs *arg) +static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg) { int status; uint32_t *p; @@ -825,8 +797,7 @@ encode_open(struct xdr_stream *xdr, struct nfs_openargs *arg) return 0; } -static int -encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg) +static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg) { uint32_t *p; @@ -839,8 +810,7 @@ encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg) } -static int -encode_open_reclaim(struct xdr_stream *xdr, struct nfs_open_reclaimargs *arg) +static int encode_open_reclaim(struct xdr_stream *xdr, const struct nfs_open_reclaimargs *arg) { uint32_t *p; @@ -874,8 +844,7 @@ encode_open_reclaim(struct xdr_stream *xdr, struct nfs_open_reclaimargs *arg) return 0; } -static int -encode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeargs *arg) +static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg) { uint32_t *p; @@ -904,8 +873,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh) return 0; } -static int -encode_putrootfh(struct xdr_stream *xdr) +static int encode_putrootfh(struct xdr_stream *xdr) { uint32_t *p; @@ -915,8 +883,7 @@ encode_putrootfh(struct xdr_stream *xdr) return 0; } -static void -encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner) +static void encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner) { extern nfs4_stateid zero_stateid; nfs4_stateid stateid; @@ -930,8 +897,7 @@ encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lock WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data)); } -static int -encode_read(struct xdr_stream *xdr, struct nfs_readargs *args) +static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) { uint32_t *p; @@ -1021,8 +987,7 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con return 0; } -static int -encode_renew(struct xdr_stream *xdr, struct nfs4_client *client_stateid) +static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid) { uint32_t *p; @@ -1033,17 +998,6 @@ encode_renew(struct xdr_stream *xdr, struct nfs4_client *client_stateid) return 0; } -static int -encode_restorefh(struct xdr_stream *xdr) -{ - uint32_t *p; - - RESERVE_SPACE(4); - WRITE32(OP_RESTOREFH); - - return 0; -} - static int encode_savefh(struct xdr_stream *xdr) { @@ -1055,9 +1009,7 @@ encode_savefh(struct xdr_stream *xdr) return 0; } -static int -encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg, - struct nfs_server *server) +static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server) { int status; uint32_t *p; @@ -1072,8 +1024,7 @@ encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg, return 0; } -static int -encode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid *setclientid) +static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid) { uint32_t total_len; uint32_t len1, len2, len3; @@ -1100,8 +1051,7 @@ encode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid *setclientid) return 0; } -static int -encode_setclientid_confirm(struct xdr_stream *xdr, struct nfs4_client *client_state) +static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state) { uint32_t *p; @@ -1113,8 +1063,7 @@ encode_setclientid_confirm(struct xdr_stream *xdr, struct nfs4_client *client_st return 0; } -static int -encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args) +static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args) { uint32_t *p; @@ -1310,8 +1259,7 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct /* * Encode a CLOSE request */ -static int -nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) +static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1332,36 +1280,26 @@ out: /* * Encode an OPEN request */ -static int -nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args) +static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { - .nops = 7, + .nops = 4, }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); status = encode_putfh(&xdr, args->fh); - if (status) - goto out; - status = encode_savefh(&xdr); if (status) goto out; status = encode_open(&xdr, args); if (status) goto out; - status = encode_getattr(&xdr, args->f_getattr); + status = encode_getfattr(&xdr, args->bitmask); if (status) goto out; status = encode_getfh(&xdr); - if (status) - goto out; - status = encode_restorefh(&xdr); - if (status) - goto out; - status = encode_getattr(&xdr, args->d_getattr); out: return status; } @@ -1369,8 +1307,7 @@ out: /* * Encode an OPEN_CONFIRM request */ -static int -nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args) +static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1391,9 +1328,7 @@ out: /* * Encode an OPEN request */ -static int -nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, - struct nfs_open_reclaimargs *args) +static int nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, struct nfs_open_reclaimargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1409,7 +1344,7 @@ nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, status = encode_open_reclaim(&xdr, args); if (status) goto out; - status = encode_getattr(&xdr, args->f_getattr); + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -1417,8 +1352,7 @@ out: /* * Encode an OPEN_DOWNGRADE request */ -static int -nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) +static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1439,8 +1373,7 @@ out: /* * Encode a LOCK request */ -static int -nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) +static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1461,8 +1394,7 @@ out: /* * Encode a LOCKT request */ -static int -nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) +static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1483,8 +1415,7 @@ out: /* * Encode a LOCKU request */ -static int -nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) +static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1547,8 +1478,7 @@ out: /* * Encode a READ request */ -static int -nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args) +static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; struct xdr_stream xdr; @@ -1580,8 +1510,7 @@ out: /* * Encode an SETATTR request */ -static int -nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args) +static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args) { struct xdr_stream xdr; @@ -1598,7 +1527,7 @@ nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs * status = encode_setattr(&xdr, args, args->server); if(status) goto out; - status = encode_getattr(&xdr, args->attr); + status = encode_getfattr(&xdr, args->bitmask); out: return status; } @@ -1606,8 +1535,7 @@ out: /* * Encode a WRITE request */ -static int -nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) +static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1628,8 +1556,7 @@ out: /* * a COMMIT request */ -static int -nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) +static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1650,8 +1577,7 @@ out: /* * FSINFO request */ -static int -nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle) +static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1713,8 +1639,7 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct n /* * a RENEW request */ -static int -nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) +static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1729,9 +1654,7 @@ nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) /* * a SETCLIENTID request */ -static int -nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, - struct nfs4_setclientid *sc) +static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1746,9 +1669,7 @@ nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, /* * a SETCLIENTID_CONFIRM request */ -static int -nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, - struct nfs4_client *clp) +static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1776,15 +1697,6 @@ nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define DECODE_TAIL \ - status = 0; \ -out: \ - return status; \ -xdr_error: \ - printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \ - status = -EIO; \ - goto out - #define READ32(x) (x) = ntohl(*p++) #define READ64(x) do { \ (x) = (u64)ntohl(*p++) << 32; \ @@ -1809,8 +1721,7 @@ xdr_error: \ } \ } while (0) -static int -decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) +static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { uint32_t *p; @@ -1825,8 +1736,7 @@ decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) return 0; } -static int -decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) { uint32_t *p; uint32_t opnum; @@ -2297,8 +2207,7 @@ static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t att return 0; } -static int -decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) +static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { uint32_t *p; @@ -2326,8 +2235,7 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) return 0; } -static int -decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) +static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) { uint32_t *p; int status; @@ -2340,8 +2248,7 @@ decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) return 0; } -static int -decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) +static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) { uint32_t *p; int status; @@ -2371,184 +2278,6 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) return 0; } -static int -decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, - struct nfs_server *server) -{ - struct nfs_fattr *nfp = getattr->gt_attrs; - uint32_t attrlen, dummy32, bmlen, - bmval0 = 0, - bmval1 = 0, - len = 0; - uint32_t *p; - unsigned int type; - int fmode = 0; - int status; - - status = decode_op_hdr(xdr, OP_GETATTR); - if (status) - return status; - - READ_BUF(4); - READ32(bmlen); - if (bmlen > 2) - goto xdr_error; - - READ_BUF((bmlen << 2) + 4); - if (bmlen > 0) - READ32(bmval0); - if (bmlen > 1) - READ32(bmval1); - READ32(attrlen); - - if ((bmval0 & ~getattr->gt_bmval[0]) || - (bmval1 & ~getattr->gt_bmval[1])) { - dprintk("read_attrs: server returned bad attributes!\n"); - goto xdr_error; - } - if (nfp) { - nfp->bitmap[0] = bmval0; - nfp->bitmap[1] = bmval1; - } - - /* - * In case the server doesn't return some attributes, - * we initialize them here to some nominal values.. - */ - if (nfp) { - nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4; - nfp->nlink = 1; - nfp->timestamp = jiffies; - } - if (bmval0 & FATTR4_WORD0_TYPE) { - READ_BUF(4); - len += 4; - READ32(type); - if (type < NF4REG || type > NF4NAMEDATTR) { - dprintk("read_attrs: bad type %d\n", type); - goto xdr_error; - } - nfp->type = nfs_type2fmt[type].nfs2type; - fmode = nfs_type2fmt[type].mode; - dprintk("read_attrs: type=%d\n", (uint32_t)nfp->type); - } - if (bmval0 & FATTR4_WORD0_CHANGE) { - READ_BUF(8); - len += 8; - READ64(nfp->change_attr); - dprintk("read_attrs: changeid=%Ld\n", (long long)nfp->change_attr); - } - if (bmval0 & FATTR4_WORD0_SIZE) { - READ_BUF(8); - len += 8; - READ64(nfp->size); - dprintk("read_attrs: size=%Ld\n", (long long)nfp->size); - } - if (bmval0 & FATTR4_WORD0_FSID) { - READ_BUF(16); - len += 16; - READ64(nfp->fsid_u.nfs4.major); - READ64(nfp->fsid_u.nfs4.minor); - dprintk("read_attrs: fsid=0x%Lx/0x%Lx\n", - (long long)nfp->fsid_u.nfs4.major, - (long long)nfp->fsid_u.nfs4.minor); - } - if (bmval0 & FATTR4_WORD0_FILEID) { - READ_BUF(8); - len += 8; - READ64(nfp->fileid); - dprintk("read_attrs: fileid=%Ld\n", (long long) nfp->fileid); - } - - if (bmval1 & FATTR4_WORD1_MODE) { - READ_BUF(4); - len += 4; - READ32(dummy32); - nfp->mode = (dummy32 & ~S_IFMT) | fmode; - dprintk("read_attrs: mode=0%o\n", nfp->mode); - } - if (bmval1 & FATTR4_WORD1_NUMLINKS) { - READ_BUF(4); - len += 4; - READ32(nfp->nlink); - dprintk("read_attrs: nlinks=0%o\n", nfp->nlink); - } - if (bmval1 & FATTR4_WORD1_OWNER) { - READ_BUF(4); - len += 4; - READ32(dummy32); /* name length */ - if (dummy32 > XDR_MAX_NETOBJ) { - dprintk("read_attrs: name too long!\n"); - goto xdr_error; - } - READ_BUF(dummy32); - len += (XDR_QUADLEN(dummy32) << 2); - if ((status = nfs_map_name_to_uid(server->nfs4_state, (char *)p, dummy32, - &nfp->uid)) < 0) { - dprintk("read_attrs: name-to-uid mapping failed!\n"); - nfp->uid = -2; - } - dprintk("read_attrs: uid=%d\n", (int)nfp->uid); - } - if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - READ_BUF(4); - len += 4; - READ32(dummy32); - if (dummy32 > XDR_MAX_NETOBJ) { - dprintk("read_attrs: name too long!\n"); - goto xdr_error; - } - READ_BUF(dummy32); - len += (XDR_QUADLEN(dummy32) << 2); - if ((status = nfs_map_group_to_gid(server->nfs4_state, (char *)p, dummy32, - &nfp->gid)) < 0) { - dprintk("read_attrs: group-to-gid mapping failed!\n"); - nfp->gid = -2; - } - dprintk("read_attrs: gid=%d\n", (int)nfp->gid); - } - if (bmval1 & FATTR4_WORD1_RAWDEV) { - uint32_t major, minor; - - READ_BUF(8); - len += 8; - READ32(major); - READ32(minor); - nfp->rdev = MKDEV(major, minor); - if (MAJOR(nfp->rdev) != major || MINOR(nfp->rdev) != minor) - nfp->rdev = 0; - dprintk("read_attrs: rdev=%u:%u\n", major, minor); - } - if (bmval1 & FATTR4_WORD1_SPACE_USED) { - READ_BUF(8); - len += 8; - READ64(nfp->du.nfs3.used); - dprintk("read_attrs: sused=0x%Lx\n", (long long) nfp->du.nfs3.used); - } - if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { - READ_BUF(12); - len += 12; - READTIME(nfp->atime); - dprintk("read_attrs: atime=%ld\n", (long)nfp->atime.tv_sec); - } - if (bmval1 & FATTR4_WORD1_TIME_METADATA) { - READ_BUF(12); - len += 12; - READTIME(nfp->ctime); - dprintk("read_attrs: ctime=%ld\n", (long)nfp->ctime.tv_sec); - } - if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { - READ_BUF(12); - len += 12; - READTIME(nfp->mtime); - dprintk("read_attrs: mtime=%ld\n", (long)nfp->mtime.tv_sec); - } - if (len != attrlen) - goto xdr_error; - - DECODE_TAIL; -} - static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) { uint32_t *savep; @@ -2672,8 +2401,7 @@ xdr_error: } -static int -decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) +static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) { uint32_t *p; uint32_t len, attrlen, bmlen, bmval0 = 0, bmval1 = 0; @@ -2775,8 +2503,7 @@ static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) /* * We create the owner, so we know a proper owner.id length is 4. */ -static int -decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied) +static int decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied) { uint32_t *p; uint32_t namelen; @@ -2793,8 +2520,7 @@ decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied) return -NFS4ERR_DENIED; } -static int -decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res) +static int decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res) { uint32_t *p; int status; @@ -2808,8 +2534,7 @@ decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res) return status; } -static int -decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res) +static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res) { int status; status = decode_op_hdr(xdr, OP_LOCKT); @@ -2818,8 +2543,7 @@ decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res) return status; } -static int -decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res) +static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res) { uint32_t *p; int status; @@ -2832,14 +2556,12 @@ decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res) return status; } -static int -decode_lookup(struct xdr_stream *xdr) +static int decode_lookup(struct xdr_stream *xdr) { return decode_op_hdr(xdr, OP_LOOKUP); } -static int -decode_open(struct xdr_stream *xdr, struct nfs_openres *res) +static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) { uint32_t *p; uint32_t bmlen, delegation_type; @@ -2851,7 +2573,7 @@ decode_open(struct xdr_stream *xdr, struct nfs_openres *res) READ_BUF(sizeof(res->stateid.data)); COPYMEM(res->stateid.data, sizeof(res->stateid.data)); - decode_change_info(xdr, res->cinfo); + decode_change_info(xdr, &res->cinfo); READ_BUF(8); READ32(res->rflags); @@ -2862,14 +2584,14 @@ decode_open(struct xdr_stream *xdr, struct nfs_openres *res) READ_BUF((bmlen << 2) + 4); p += bmlen; READ32(delegation_type); - if (delegation_type != NFS4_OPEN_DELEGATE_NONE) - goto xdr_error; - - DECODE_TAIL; + if (delegation_type == NFS4_OPEN_DELEGATE_NONE) + return 0; +xdr_error: + printk(KERN_NOTICE "%s: xdr error!\n", __FUNCTION__); + return -EIO; } -static int -decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) +static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) { uint32_t *p; int status; @@ -2882,8 +2604,7 @@ decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) return 0; } -static int -decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res) +static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res) { uint32_t *p; int status; @@ -2896,20 +2617,17 @@ decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res) return 0; } -static int -decode_putfh(struct xdr_stream *xdr) +static int decode_putfh(struct xdr_stream *xdr) { return decode_op_hdr(xdr, OP_PUTFH); } -static int -decode_putrootfh(struct xdr_stream *xdr) +static int decode_putrootfh(struct xdr_stream *xdr) { return decode_op_hdr(xdr, OP_PUTROOTFH); } -static int -decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) +static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) { struct iovec *iov = req->rq_rvec; uint32_t *p; @@ -3061,12 +2779,6 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) return 0; } -static int -decode_restorefh(struct xdr_stream *xdr) -{ - return decode_op_hdr(xdr, OP_RESTOREFH); -} - static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) { int status; @@ -3094,8 +2806,7 @@ out: return status; } -static int -decode_renew(struct xdr_stream *xdr) +static int decode_renew(struct xdr_stream *xdr) { return decode_op_hdr(xdr, OP_RENEW); } @@ -3106,8 +2817,7 @@ decode_savefh(struct xdr_stream *xdr) return decode_op_hdr(xdr, OP_SAVEFH); } -static int -decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) +static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) { uint32_t *p; uint32_t bmlen; @@ -3123,8 +2833,7 @@ decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) return 0; } -static int -decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) +static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) { uint32_t *p; uint32_t opnum; @@ -3162,14 +2871,12 @@ decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) return 0; } -static int -decode_setclientid_confirm(struct xdr_stream *xdr) +static int decode_setclientid_confirm(struct xdr_stream *xdr) { return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM); } -static int -decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) +static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) { uint32_t *p; int status; @@ -3188,8 +2895,7 @@ decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) /* * Decode OPEN_DOWNGRADE response */ -static int -nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) +static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3385,8 +3091,7 @@ out: /* * Decode CLOSE response */ -static int -nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) +static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3407,8 +3112,7 @@ out: /* * Decode OPEN response */ -static int -nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) +static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3419,26 +3123,15 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) if (status) goto out; status = decode_putfh(&xdr); - if (status) - goto out; - status = decode_savefh(&xdr); if (status) goto out; status = decode_open(&xdr, res); if (status) goto out; - status = decode_getattr(&xdr, res->f_getattr, res->server); + status = decode_getfattr(&xdr, res->f_attr, res->server); if (status) goto out; status = decode_getfh(&xdr, &res->fh); - if (status) - goto out; - status = decode_restorefh(&xdr); - if (status) - goto out; - status = decode_getattr(&xdr, res->d_getattr, res->server); - if (status) - goto out; out: return status; } @@ -3446,8 +3139,7 @@ out: /* * Decode OPEN_CONFIRM response */ -static int -nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res) +static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3468,8 +3160,7 @@ out: /* * Decode OPEN_RECLAIM response */ -static int -nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) +static int nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3485,7 +3176,7 @@ nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openre status = decode_open(&xdr, res); if (status) goto out; - status = decode_getattr(&xdr, res->f_getattr, res->server); + status = decode_getfattr(&xdr, res->f_attr, res->server); out: return status; } @@ -3493,8 +3184,7 @@ out: /* * Decode SETATTR response */ -static int -nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res) +static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3510,7 +3200,7 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres status = decode_setattr(&xdr, res); if (status) goto out; - status = decode_getattr(&xdr, res->attr, res->server); + status = decode_getfattr(&xdr, res->fattr, res->server); out: return status; } @@ -3518,8 +3208,7 @@ out: /* * Decode LOCK response */ -static int -nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) +static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3540,8 +3229,7 @@ out: /* * Decode LOCKT response */ -static int -nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) +static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3562,8 +3250,7 @@ out: /* * Decode LOCKU response */ -static int -nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) +static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3626,8 +3313,7 @@ out: /* * Decode Read response */ -static int -nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res) +static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3650,8 +3336,7 @@ out: /* * Decode WRITE response */ -static int -nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res) +static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3674,8 +3359,7 @@ out: /* * Decode COMMIT response */ -static int -nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res) +static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3696,8 +3380,7 @@ out: /* * FSINFO request */ -static int -nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo) +static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3753,8 +3436,7 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fss /* * Decode RENEW response */ -static int -nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) +static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3770,8 +3452,7 @@ nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) /* * a SETCLIENTID request */ -static int -nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, +static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) { struct xdr_stream xdr; @@ -3790,8 +3471,7 @@ nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, /* * a SETCLIENTID_CONFIRM request */ -static int -nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo) +static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3810,8 +3490,7 @@ nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_f return status; } -uint32_t * -nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) +uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) { uint32_t len; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index c77d4205959b..62bcc729af6c 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -89,6 +89,12 @@ struct nfs_pathconf { __u32 max_namelen; /* max name length */ }; +struct nfs4_change_info { + u32 atomic; + u64 before; + u64 after; +}; + /* * Arguments to the open call. */ @@ -104,20 +110,18 @@ struct nfs_openargs { struct iattr * attrs; /* UNCHECKED, GUARDED */ nfs4_verifier verifier; /* EXCLUSIVE */ } u; - struct qstr * name; - struct nfs4_getattr * f_getattr; - struct nfs4_getattr * d_getattr; - struct nfs_server * server; /* Needed for ID mapping */ + const struct qstr * name; + const struct nfs_server *server; /* Needed for ID mapping */ + const u32 * bitmask; }; struct nfs_openres { nfs4_stateid stateid; struct nfs_fh fh; - struct nfs4_change_info * cinfo; + struct nfs4_change_info cinfo; __u32 rflags; - struct nfs4_getattr * f_getattr; - struct nfs4_getattr * d_getattr; - struct nfs_server * server; + struct nfs_fattr * f_attr; + const struct nfs_server *server; }; /* @@ -143,7 +147,7 @@ struct nfs_open_reclaimargs { __u32 id; __u32 share_access; __u32 claim; - struct nfs4_getattr * f_getattr; + const __u32 * bitmask; }; /* @@ -217,7 +221,7 @@ struct nfs_lockres { nfs4_stateid stateid;/* LOCK success, LOCKU */ struct nfs_lock_denied denied; /* LOCK failed, LOCKT success */ } u; - struct nfs_server * server; + const struct nfs_server * server; }; /* @@ -323,13 +327,13 @@ struct nfs_setattrargs { struct nfs_fh * fh; nfs4_stateid stateid; struct iattr * iap; - struct nfs4_getattr * attr; - struct nfs_server * server; /* Needed for name mapping */ + const struct nfs_server * server; /* Needed for name mapping */ + const u32 * bitmask; }; struct nfs_setattrres { - struct nfs4_getattr * attr; - struct nfs_server * server; + struct nfs_fattr * fattr; + const struct nfs_server * server; }; struct nfs_linkargs { @@ -480,12 +484,6 @@ struct nfs3_readdirres { typedef u64 clientid4; -struct nfs4_change_info { - u32 atomic; - u64 before; - u64 after; -}; - struct nfs4_accessargs { const struct nfs_fh * fh; u32 access; @@ -519,12 +517,6 @@ struct nfs4_create_res { struct nfs4_change_info dir_cinfo; }; -struct nfs4_getattr { - u32 * gt_bmval; /* request */ - struct nfs_fattr * gt_attrs; /* response */ - struct nfs_fsstat * gt_fsstat; /* response */ -}; - struct nfs4_getattr_arg { const struct nfs_fh * fh; const u32 * bitmask; -- cgit v1.2.3 From d9d762e75ae8b2d55bf94b869c82206715a53f0b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:40:18 -0700 Subject: NFSv4: clean up the FSINFO XDR code to conform to the new scheme for GETATTR. --- fs/nfs/nfs4proc.c | 17 ++++- fs/nfs/nfs4xdr.c | 178 ++++++++++++++++++++++++++++++------------------ include/linux/nfs_xdr.h | 5 ++ 3 files changed, 129 insertions(+), 71 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c3e1046cd445..d86d64211925 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -72,7 +72,7 @@ static inline int nfs4_map_errors(int err) /* * This is our standard bitmap for GETATTR requests. */ -u32 nfs4_fattr_bitmap[2] = { +const u32 nfs4_fattr_bitmap[2] = { FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE @@ -89,7 +89,7 @@ u32 nfs4_fattr_bitmap[2] = { | FATTR4_WORD1_TIME_MODIFY }; -u32 nfs4_statfs_bitmap[2] = { +const u32 nfs4_statfs_bitmap[2] = { FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL, @@ -104,6 +104,13 @@ u32 nfs4_pathconf_bitmap[2] = { 0 }; +const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE + | FATTR4_WORD0_MAXREAD + | FATTR4_WORD0_MAXWRITE + | FATTR4_WORD0_LEASE_TIME, + 0 +}; + static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, struct nfs4_readdir_arg *readdir) { @@ -1198,9 +1205,13 @@ static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) { + struct nfs4_fsinfo_arg args = { + .fh = fhandle, + .bitmask = nfs4_fsinfo_bitmap, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], - .rpc_argp = fhandle, + .rpc_argp = &args, .rpc_resp = fsinfo, }; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index ff24d28fc6f3..10c5ffbcf640 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -624,12 +624,12 @@ static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) bitmask[1] & nfs4_fattr_bitmap[1]); } -static int encode_fsinfo(struct xdr_stream *xdr) +static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) { - return encode_getattr_one(xdr, FATTR4_WORD0_MAXFILESIZE - | FATTR4_WORD0_MAXREAD - | FATTR4_WORD0_MAXWRITE - | FATTR4_WORD0_LEASE_TIME); + extern u32 nfs4_fsinfo_bitmap[]; + + return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], + bitmask[1] & nfs4_fsinfo_bitmap[1]); } static int encode_getfh(struct xdr_stream *xdr) @@ -1577,7 +1577,7 @@ out: /* * FSINFO request */ -static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle) +static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1587,9 +1587,9 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle) xdr_init_encode(&xdr, &req->rq_snd_buf, p); encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, fhandle); + status = encode_putfh(&xdr, args->fh); if (!status) - status = encode_fsinfo(&xdr); + status = encode_fsinfo(&xdr, args->bitmask); return status; } @@ -1675,6 +1675,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s struct compound_hdr hdr = { .nops = 3, }; + const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); @@ -1683,7 +1684,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s if (!status) status = encode_putrootfh(&xdr); if (!status) - status = encode_fsinfo(&xdr); + status = encode_fsinfo(&xdr, lease_bitmap); return status; } @@ -1857,6 +1858,22 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs return 0; } +static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + + *res = 60; + if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) { + READ_BUF(4); + READ32(*res); + bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME; + } + dprintk("%s: file size=%u\n", __FUNCTION__, (unsigned int)*res); + return 0; +} + static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) { uint32_t *p; @@ -1924,6 +1941,23 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin return status; } +static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) { + READ_BUF(8); + READ64(*res); + bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE; + } + dprintk("%s: maxfilesize=%Lu\n", __FUNCTION__, (unsigned long long)*res); + return status; +} + static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink) { uint32_t *p; @@ -1958,6 +1992,48 @@ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ return status; } +static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 1024; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) { + uint64_t maxread; + READ_BUF(8); + READ64(maxread); + if (maxread > 0x7FFFFFFF) + maxread = 0x7FFFFFFF; + *res = (uint32_t)maxread; + bitmap[0] &= ~FATTR4_WORD0_MAXREAD; + } + dprintk("%s: maxread=%lu\n", __FUNCTION__, (unsigned long)*res); + return status; +} + +static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + int status = 0; + + *res = 1024; + if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) { + uint64_t maxwrite; + READ_BUF(8); + READ64(maxwrite); + if (maxwrite > 0x7FFFFFFF) + maxwrite = 0x7FFFFFFF; + *res = (uint32_t)maxwrite; + bitmap[0] &= ~FATTR4_WORD0_MAXWRITE; + } + dprintk("%s: maxwrite=%lu\n", __FUNCTION__, (unsigned long)*res); + return status; +} + static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode) { uint32_t *p; @@ -2403,69 +2479,35 @@ xdr_error: static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) { - uint32_t *p; - uint32_t len, attrlen, bmlen, bmval0 = 0, bmval1 = 0; + uint32_t *savep; + uint32_t attrlen, bitmap[2]; int status; - status = decode_op_hdr(xdr, OP_GETATTR); - if (status) - return status; - READ_BUF(4); - READ32(bmlen); - if (bmlen < 1) - return -EIO; - READ_BUF(bmlen << 2); - READ32(bmval0); - if (bmval0 & ~(FATTR4_WORD0_MAXFILESIZE|FATTR4_WORD0_MAXREAD| - FATTR4_WORD0_MAXWRITE|FATTR4_WORD0_LEASE_TIME)) - goto out_bad_bitmap; - if (bmlen > 1) { - READ32(bmval1); - if (bmval1 != 0 || bmlen > 2) - goto out_bad_bitmap; - } - READ_BUF(4); - READ32(attrlen); - READ_BUF(attrlen); + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto xdr_error; + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto xdr_error; + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) + goto xdr_error; + fsinfo->rtmult = fsinfo->wtmult = 512; /* ??? */ - fsinfo->lease_time = 60; - len = attrlen; - if (bmval0 & FATTR4_WORD0_LEASE_TIME) { - len -= 4; - READ32(fsinfo->lease_time); - dprintk("read_attrs: lease_time=%d\n", fsinfo->lease_time); - } - if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { - len -= 8; - READ64(fsinfo->maxfilesize); - dprintk("read_attrs: maxfilesize=0x%Lx\n", (long long) fsinfo->maxfilesize); - } - if (bmval0 & FATTR4_WORD0_MAXREAD) { - len -= 8; - READ64(fsinfo->rtmax); - fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax; - dprintk("read_attrs: maxread=%d\n", fsinfo->rtmax); - } - if (bmval0 & FATTR4_WORD0_MAXWRITE) { - len -= 8; - READ64(fsinfo->wtmax); - fsinfo->wtpref = fsinfo->wtmax; - dprintk("read_attrs: maxwrite=%d\n", fsinfo->wtmax); - } - if (len != 0) - goto out_bad_attrlen; - return 0; -out_bad_attrlen: - printk(KERN_NOTICE "%s: server attribute length %u does not match bitmap 0x%x/0x%x\n", - __FUNCTION__, (unsigned int)attrlen, - (unsigned int) bmval0, (unsigned int)bmval1); - return -EIO; -out_bad_bitmap: - printk(KERN_NOTICE "%s: server returned bad attribute bitmap 0x%x/0x%x\n", - __FUNCTION__, - (unsigned int)bmval0, (unsigned int)bmval1); - return -EIO; + if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0) + goto xdr_error; + if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0) + goto xdr_error; + if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0) + goto xdr_error; + fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax; + if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0) + goto xdr_error; + fsinfo->wtpref = fsinfo->wtmax; + + status = verify_attr_len(xdr, savep, attrlen); +xdr_error: + if (status != 0) + printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + return status; } static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 62bcc729af6c..30418767ece3 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -517,6 +517,11 @@ struct nfs4_create_res { struct nfs4_change_info dir_cinfo; }; +struct nfs4_fsinfo_arg { + const struct nfs_fh * fh; + const u32 * bitmask; +}; + struct nfs4_getattr_arg { const struct nfs_fh * fh; const u32 * bitmask; -- cgit v1.2.3 From 64596af09b60f5e5dcf563a9ff72a7773484faee Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:42:23 -0700 Subject: RPC: add a field to the xdr_buf that explicitly contains the maximum buffer length. RPC: make the client receive xdr_buf return the actual length of the RPC length. NFSv4/RPC: improved checks to prevent XDR reading beyond the actual end of the RPC reply. --- fs/nfs/nfs2xdr.c | 6 +- fs/nfs/nfs3xdr.c | 6 +- fs/nfs/nfs4xdr.c | 6 +- include/linux/sunrpc/xdr.h | 83 ++---------------------- include/linux/sunrpc/xprt.h | 2 - net/sunrpc/clnt.c | 10 ++- net/sunrpc/sunrpc_syms.c | 2 - net/sunrpc/xdr.c | 154 ++++++++++++++++++++++++++++++++++++++++---- net/sunrpc/xprt.c | 6 +- 9 files changed, 168 insertions(+), 107 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 138afa28c742..61f5e8105392 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -231,7 +231,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) static int nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) { - struct iovec *iov = req->rq_rvec; + struct iovec *iov = req->rq_rcv_buf.head; int status, count, recvd, hdrlen; if ((status = ntohl(*p++))) @@ -250,7 +250,7 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); } - recvd = req->rq_received - hdrlen; + recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { printk(KERN_WARNING "NFS: server cheating in read reply: " "count %d > recvd %d\n", count, recvd); @@ -396,7 +396,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) } pglen = rcvbuf->page_len; - recvd = req->rq_received - hdrlen; + recvd = rcvbuf->len - hdrlen; if (pglen > recvd) pglen = recvd; page = rcvbuf->pages; diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 908bff184178..af67338476ef 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -515,7 +515,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res) } pglen = rcvbuf->page_len; - recvd = req->rq_received - hdrlen; + recvd = rcvbuf->len - hdrlen; if (pglen > recvd) pglen = recvd; page = rcvbuf->pages; @@ -758,7 +758,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) static int nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) { - struct iovec *iov = req->rq_rvec; + struct iovec *iov = req->rq_rcv_buf.head; int status, count, ocount, recvd, hdrlen; status = ntohl(*p++); @@ -789,7 +789,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); } - recvd = req->rq_received - hdrlen; + recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { printk(KERN_WARNING "NFS: server cheating in read reply: " "count %d > recvd %d\n", count, recvd); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 10c5ffbcf640..ffea69b7df37 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2671,7 +2671,7 @@ static int decode_putrootfh(struct xdr_stream *xdr) static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) { - struct iovec *iov = req->rq_rvec; + struct iovec *iov = req->rq_rcv_buf.head; uint32_t *p; uint32_t count, eof, recvd, hdrlen; int status; @@ -2683,7 +2683,7 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ READ32(eof); READ32(count); hdrlen = (u8 *) p - (u8 *) iov->iov_base; - recvd = req->rq_received - hdrlen; + recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { printk(KERN_WARNING "NFS: server cheating in read reply: " "count %u > recvd %u\n", count, recvd); @@ -2713,7 +2713,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n COPYMEM(readdir->verifier.data, 8); hdrlen = (char *) p - (char *) iov->iov_base; - recvd = req->rq_received - hdrlen; + recvd = rcvbuf->len - hdrlen; if (pglen > recvd) pglen = recvd; xdr_read_pages(xdr, pglen); diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index deac01c2e96a..c48fc7d65b1b 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -55,7 +55,8 @@ struct xdr_buf { unsigned int page_base, /* Start of page data */ page_len; /* Length of page data */ - unsigned int len; /* Total length of data */ + unsigned int buflen, /* Total length of storage buffer */ + len; /* Length of XDR encoded message */ }; @@ -183,86 +184,14 @@ struct xdr_stream { struct iovec *iov; /* pointer to the current iovec */ }; -/* - * Initialize an xdr_stream for encoding data. - * - * Note: at the moment the RPC client only passes the length of our - * scratch buffer in the xdr_buf's header iovec. Previously this - * meant we needed to call xdr_adjust_iovec() after encoding the - * data. With the new scheme, the xdr_stream manages the details - * of the buffer length, and takes care of adjusting the iovec - * length for us. - */ -static inline void -xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) -{ - struct iovec *iov = buf->head; - - xdr->buf = buf; - xdr->iov = iov; - xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); - buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base; - xdr->p = p; -} - -/* - * Check that we have enough buffer space to encode 'nbytes' more - * bytes of data. If so, update the total xdr_buf length, and - * adjust the length of the current iovec. - */ -static inline uint32_t * -xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) -{ - uint32_t *p = xdr->p; - uint32_t *q; - - /* align nbytes on the next 32-bit boundary */ - nbytes += 3; - nbytes &= ~3; - q = p + (nbytes >> 2); - if (unlikely(q > xdr->end || q < p)) - return NULL; - xdr->p = q; - xdr->iov->iov_len += nbytes; - xdr->buf->len += nbytes; - return p; -} - +extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p); +extern uint32_t *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base, unsigned int len); +extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p); +extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len); -/* - * Initialize an xdr_stream for decoding data. - */ -static inline void -xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) -{ - struct iovec *iov = buf->head; - xdr->buf = buf; - xdr->iov = iov; - xdr->p = p; - xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); -} - -/* - * Check if the input buffer is long enough to enable us to decode - * 'nbytes' more bytes of data starting at the current position. - * If so return the current pointer, then update the current - * position. - */ -static inline uint32_t * -xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) -{ - uint32_t *p = xdr->p; - uint32_t *q = p + XDR_QUADLEN(nbytes); - - if (unlikely(q > xdr->end || q < p)) - return NULL; - xdr->p = q; - return p; -} - #endif /* __KERNEL__ */ #endif /* _SUNRPC_XDR_H_ */ diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index e6d79afcb50c..52e4e03016fc 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -120,8 +120,6 @@ struct rpc_rqst { }; #define rq_svec rq_snd_buf.head #define rq_slen rq_snd_buf.len -#define rq_rvec rq_rcv_buf.head -#define rq_rlen rq_rcv_buf.len #define XPRT_LAST_FRAG (1 << 0) #define XPRT_COPY_RECM (1 << 1) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 9b0601699e69..1696c16b2bc9 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -605,11 +605,13 @@ call_encode(struct rpc_task *task) sndbuf->tail[0].iov_len = 0; sndbuf->page_len = 0; sndbuf->len = 0; + sndbuf->buflen = bufsiz; rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz); rcvbuf->head[0].iov_len = bufsiz; rcvbuf->tail[0].iov_len = 0; rcvbuf->page_len = 0; - rcvbuf->len = bufsiz; + rcvbuf->len = 0; + rcvbuf->buflen = bufsiz; /* Encode header and provided arguments */ encode = task->tk_msg.rpc_proc->p_encode; @@ -849,6 +851,8 @@ call_decode(struct rpc_task *task) return; } + req->rq_rcv_buf.len = req->rq_private_buf.len; + /* Check that the softirq receive buffer is valid */ WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf, sizeof(req->rq_rcv_buf)) != 0); @@ -884,7 +888,7 @@ call_decode(struct rpc_task *task) task->tk_status); return; out_retry: - req->rq_received = 0; + req->rq_received = req->rq_private_buf.len = 0; task->tk_status = 0; } @@ -956,7 +960,7 @@ call_header(struct rpc_task *task) static u32 * call_verify(struct rpc_task *task) { - u32 *p = task->tk_rqstp->rq_rvec[0].iov_base, n; + u32 *p = task->tk_rqstp->rq_rcv_buf.head[0].iov_base, n; p += 1; /* skip XID */ diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 104bd5679272..91e13c9d96fe 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -128,8 +128,6 @@ EXPORT_SYMBOL(xdr_encode_netobj); EXPORT_SYMBOL(xdr_encode_pages); EXPORT_SYMBOL(xdr_inline_pages); EXPORT_SYMBOL(xdr_shift_buf); -EXPORT_SYMBOL(xdr_write_pages); -EXPORT_SYMBOL(xdr_read_pages); EXPORT_SYMBOL(xdr_buf_from_iov); EXPORT_SYMBOL(xdr_buf_subsegment); EXPORT_SYMBOL(xdr_buf_read_netobj); diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index a0b977cfbfc5..04804373ce6c 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -160,6 +160,7 @@ xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, tail->iov_len = pad; len += pad; } + xdr->buflen += len; xdr->len += len; } @@ -181,7 +182,7 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, tail->iov_base = buf + offset; tail->iov_len = buflen - offset; - xdr->len += len; + xdr->buflen += len; } /* @@ -675,7 +676,10 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len) copy); } head->iov_len -= len; - buf->len -= len; + buf->buflen -= len; + /* Have we truncated the message? */ + if (buf->len > buf->buflen) + buf->len = buf->buflen; } /* @@ -705,7 +709,7 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) copy = tail->iov_len - len; memmove(p, tail->iov_base, copy); } else - buf->len -= len; + buf->buflen -= len; /* Copy from the inlined pages into the tail */ copy = len; if (copy > tail->iov_len) @@ -715,7 +719,10 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) copy); } buf->page_len -= len; - buf->len -= len; + buf->buflen -= len; + /* Have we truncated the message? */ + if (buf->len > buf->buflen) + buf->len = buf->buflen; } void @@ -724,8 +731,67 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len) xdr_shrink_bufhead(buf, len); } -void -xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base, +/** + * xdr_init_encode - Initialize a struct xdr_stream for sending data. + * @xdr: pointer to xdr_stream struct + * @buf: pointer to XDR buffer in which to encode data + * @p: current pointer inside XDR buffer + * + * Note: at the moment the RPC client only passes the length of our + * scratch buffer in the xdr_buf's header iovec. Previously this + * meant we needed to call xdr_adjust_iovec() after encoding the + * data. With the new scheme, the xdr_stream manages the details + * of the buffer length, and takes care of adjusting the iovec + * length for us. + */ +void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) +{ + struct iovec *iov = buf->head; + + xdr->buf = buf; + xdr->iov = iov; + xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); + buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base; + xdr->p = p; +} +EXPORT_SYMBOL(xdr_init_encode); + +/** + * xdr_reserve_space - Reserve buffer space for sending + * @xdr: pointer to xdr_stream + * @nbytes: number of bytes to reserve + * + * Checks that we have enough buffer space to encode 'nbytes' more + * bytes of data. If so, update the total xdr_buf length, and + * adjust the length of the current iovec. + */ +uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) +{ + uint32_t *p = xdr->p; + uint32_t *q; + + /* align nbytes on the next 32-bit boundary */ + nbytes += 3; + nbytes &= ~3; + q = p + (nbytes >> 2); + if (unlikely(q > xdr->end || q < p)) + return NULL; + xdr->p = q; + xdr->iov->iov_len += nbytes; + xdr->buf->len += nbytes; + return p; +} +EXPORT_SYMBOL(xdr_reserve_space); + +/** + * xdr_write_pages - Insert a list of pages into an XDR buffer for sending + * @xdr: pointer to xdr_stream + * @pages: list of pages + * @base: offset of first byte + * @len: length of data in bytes + * + */ +void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base, unsigned int len) { struct xdr_buf *buf = xdr->buf; @@ -747,15 +813,69 @@ xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base, len += pad; *xdr->p++ = 0; } + buf->buflen += len; buf->len += len; } +EXPORT_SYMBOL(xdr_write_pages); -void -xdr_read_pages(struct xdr_stream *xdr, unsigned int len) +/** + * xdr_init_decode - Initialize an xdr_stream for decoding data. + * @xdr: pointer to xdr_stream struct + * @buf: pointer to XDR buffer from which to decode data + * @p: current pointer inside XDR buffer + */ +void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) +{ + struct iovec *iov = buf->head; + unsigned int len = iov->iov_len; + + if (len > buf->len) + len = buf->len; + xdr->buf = buf; + xdr->iov = iov; + xdr->p = p; + xdr->end = (uint32_t *)((char *)iov->iov_base + len); +} +EXPORT_SYMBOL(xdr_init_decode); + +/** + * xdr_inline_decode - Retrieve non-page XDR data to decode + * @xdr: pointer to xdr_stream struct + * @nbytes: number of bytes of data to decode + * + * Check if the input buffer is long enough to enable us to decode + * 'nbytes' more bytes of data starting at the current position. + * If so return the current pointer, then update the current + * pointer position. + */ +uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) +{ + uint32_t *p = xdr->p; + uint32_t *q = p + XDR_QUADLEN(nbytes); + + if (unlikely(q > xdr->end || q < p)) + return NULL; + xdr->p = q; + return p; +} +EXPORT_SYMBOL(xdr_inline_decode); + +/** + * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position + * @xdr: pointer to xdr_stream struct + * @len: number of bytes of page data + * + * Moves data beyond the current pointer position from the XDR head[] buffer + * into the page list. Any data that lies beyond current position + "len" + * bytes is moved into the XDR tail[]. The current pointer is then + * repositioned at the beginning of the XDR tail. + */ +void xdr_read_pages(struct xdr_stream *xdr, unsigned int len) { struct xdr_buf *buf = xdr->buf; struct iovec *iov; ssize_t shift; + unsigned int end; int padding; /* Realign pages to current pointer position */ @@ -769,9 +889,21 @@ xdr_read_pages(struct xdr_stream *xdr, unsigned int len) xdr_shrink_pagelen(buf, buf->page_len - len); padding = (XDR_QUADLEN(len) << 2) - len; xdr->iov = iov = buf->tail; + /* Compute remaining message length. */ + end = iov->iov_len; + shift = buf->buflen - buf->len; + if (shift < end) + end -= shift; + else if (shift > 0) + end = 0; + /* + * Position current pointer at beginning of tail, and + * set remaining message length. + */ xdr->p = (uint32_t *)((char *)iov->iov_base + padding); - xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); + xdr->end = (uint32_t *)((char *)iov->iov_base + end); } +EXPORT_SYMBOL(xdr_read_pages); static struct iovec empty_iov = {.iov_base = NULL, .iov_len = 0}; @@ -781,7 +913,7 @@ xdr_buf_from_iov(struct iovec *iov, struct xdr_buf *buf) buf->head[0] = *iov; buf->tail[0] = empty_iov; buf->page_len = 0; - buf->len = iov->iov_len; + buf->buflen = buf->len = iov->iov_len; } /* Sets subiov to the intersection of iov with the buffer of length len @@ -811,7 +943,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf, { int i; - subbuf->len = len; + subbuf->buflen = subbuf->len = len; iov_subsegment(buf->head, subbuf->head, &base, &len); if (base < buf->page_len) { diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c15af4794892..8b9696d39e5e 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -647,8 +647,8 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) #endif dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied); - req->rq_received = copied; list_del_init(&req->rq_list); + req->rq_received = req->rq_private_buf.len = copied; /* ... and wake up the process. */ rpc_wake_up_task(task); @@ -765,7 +765,7 @@ udp_data_ready(struct sock *sk, int len) dprintk("RPC: %4d received reply\n", task->tk_pid); - if ((copied = rovr->rq_private_buf.len) > repsize) + if ((copied = rovr->rq_private_buf.buflen) > repsize) copied = repsize; /* Suck it into the iovec, verify checksum if not done by hw. */ @@ -908,7 +908,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) xprt->tcp_copied += len; xprt->tcp_offset += len; - if (xprt->tcp_copied == req->rq_private_buf.len) + if (xprt->tcp_copied == req->rq_private_buf.buflen) xprt->tcp_flags &= ~XPRT_COPY_DATA; else if (xprt->tcp_offset == xprt->tcp_reclen) { if (xprt->tcp_flags & XPRT_LAST_FRAG) -- cgit v1.2.3 From 4e2cf61913691c2820ff3d748c4ec81633e8e011 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:43:43 -0700 Subject: NFSv4: Check server capabilities at mount time so that we can optimize away requests for attributes that are not supported. In particular, we wish to determine whether or not the server supports ACLs. --- fs/nfs/nfs4proc.c | 76 +++++++++++++++++++------- fs/nfs/nfs4xdr.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/nfs4.h | 6 +++ include/linux/nfs_fs_sb.h | 11 +++- include/linux/nfs_xdr.h | 7 +++ 5 files changed, 213 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d86d64211925..6060f32d751d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -204,7 +204,7 @@ nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) .share_access = state->state, .clientid = server->nfs4_state->cl_clientid, .claim = NFS4_OPEN_CLAIM_PREVIOUS, - .bitmask = nfs4_fattr_bitmap, + .bitmask = server->attr_bitmask, }; struct nfs_openres o_res = { .f_attr = &fattr, @@ -248,7 +248,7 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt .createmode = (flags & O_EXCL) ? NFS4_CREATE_EXCLUSIVE : NFS4_CREATE_UNCHECKED, .name = name, .server = server, - .bitmask = nfs4_fattr_bitmap, + .bitmask = server->attr_bitmask, }; struct nfs_openres o_res = { .f_attr = &f_attr, @@ -370,7 +370,7 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, .fh = fhandle, .iap = sattr, .server = server, - .bitmask = nfs4_fattr_bitmap, + .bitmask = server->attr_bitmask, }; struct nfs_setattrres res = { .fattr = fattr, @@ -517,6 +517,31 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) return 0; } + +static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) +{ + struct nfs4_server_caps_res res = {}; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], + .rpc_argp = fhandle, + .rpc_resp = &res, + }; + int status; + + status = rpc_call_sync(server->client, &msg, 0); + if (status == 0) { + memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); + if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) + server->caps |= NFS_CAP_ACLS; + if (res.has_links != 0) + server->caps |= NFS_CAP_HARDLINKS; + if (res.has_symlinks != 0) + server->caps |= NFS_CAP_SYMLINKS; + server->acl_bitmask = res.acl_bitmask; + } + return status; +} + static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { @@ -591,6 +616,8 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, } break; } + if (status == 0) + status = nfs4_server_capabilities(server, fhandle); if (status == 0) status = nfs4_do_fsinfo(server, fhandle, info); out: @@ -599,13 +626,14 @@ out: static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) { + struct nfs_server *server = NFS_SERVER(inode); struct nfs4_getattr_arg args = { .fh = NFS_FH(inode), - .bitmask = nfs4_fattr_bitmap, + .bitmask = server->attr_bitmask, }; struct nfs4_getattr_res res = { .fattr = fattr, - .server = NFS_SERVER(inode), + .server = server, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], @@ -681,13 +709,14 @@ 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 = nfs4_fattr_bitmap, + .bitmask = server->attr_bitmask, .dir_fh = NFS_FH(dir), .name = name, }; struct nfs4_lookup_res res = { - .server = NFS_SERVER(dir), + .server = server, .fattr = fattr, .fh = fhandle, }; @@ -1046,16 +1075,17 @@ static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { + struct nfs_server *server = NFS_SERVER(dir); struct nfs4_create_arg arg = { .dir_fh = NFS_FH(dir), - .server = NFS_SERVER(dir), + .server = server, .name = name, .attrs = sattr, .ftype = NF4LNK, - .bitmask = nfs4_fattr_bitmap, + .bitmask = server->attr_bitmask, }; struct nfs4_create_res res = { - .server = NFS_SERVER(dir), + .server = server, .fh = fhandle, .fattr = fattr, }; @@ -1079,16 +1109,17 @@ static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { + struct nfs_server *server = NFS_SERVER(dir); struct nfs4_create_arg arg = { .dir_fh = NFS_FH(dir), - .server = NFS_SERVER(dir), + .server = server, .name = name, .attrs = sattr, .ftype = NF4DIR, - .bitmask = nfs4_fattr_bitmap, + .bitmask = server->attr_bitmask, }; struct nfs4_create_res res = { - .server = NFS_SERVER(dir), + .server = server, .fh = fhandle, .fattr = fattr, }; @@ -1140,15 +1171,16 @@ static int nfs4_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr) { + struct nfs_server *server = NFS_SERVER(dir); struct nfs4_create_arg arg = { .dir_fh = NFS_FH(dir), - .server = NFS_SERVER(dir), + .server = server, .name = name, .attrs = sattr, - .bitmask = nfs4_fattr_bitmap, + .bitmask = server->attr_bitmask, }; struct nfs4_create_res res = { - .server = NFS_SERVER(dir), + .server = server, .fh = fh, .fattr = fattr, }; @@ -1190,7 +1222,7 @@ static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, { struct nfs4_statfs_arg args = { .fh = fhandle, - .bitmask = nfs4_statfs_bitmap, + .bitmask = server->attr_bitmask, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], @@ -1207,7 +1239,7 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, { struct nfs4_fsinfo_arg args = { .fh = fhandle, - .bitmask = nfs4_fsinfo_bitmap, + .bitmask = server->attr_bitmask, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], @@ -1229,7 +1261,7 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, { struct nfs4_pathconf_arg args = { .fh = fhandle, - .bitmask = nfs4_pathconf_bitmap, + .bitmask = server->attr_bitmask, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], @@ -1237,6 +1269,12 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, .rpc_resp = pathconf, }; + /* None of the pathconf attributes are mandatory to implement */ + if ((args.bitmask[0] & nfs4_pathconf_bitmap[0]) == 0) { + memset(pathconf, 0, sizeof(*pathconf)); + return 0; + } + pathconf->fattr->valid = 0; return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index ffea69b7df37..0e12e772d255 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -335,6 +335,10 @@ static int nfs_stat_to_errno(int); #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ op_decode_hdr_maxsz + 12) +#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ + decode_getattr_maxsz) static struct { unsigned int mode; @@ -1636,6 +1640,28 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct n return status; } +/* + * GETATTR_BITMAP request + */ +static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, fhandle); + if (status == 0) + status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| + FATTR4_WORD0_LINK_SUPPORT| + FATTR4_WORD0_SYMLINK_SUPPORT| + FATTR4_WORD0_ACLSUPPORT); + return status; +} + /* * a RENEW request */ @@ -1785,6 +1811,17 @@ static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, return 0; } +static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask) +{ + if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) { + decode_attr_bitmap(xdr, bitmask); + bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; + } else + bitmask[0] = bitmask[1] = 0; + dprintk("%s: bitmask=0x%x%x\n", __FUNCTION__, bitmask[0], bitmask[1]); + return 0; +} + static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type) { uint32_t *p; @@ -1838,6 +1875,38 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t * return 0; } +static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) { + READ_BUF(4); + READ32(*res); + bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT; + } + dprintk("%s: link support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true"); + return 0; +} + +static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + + *res = 0; + if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) { + READ_BUF(4); + READ32(*res); + bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT; + } + dprintk("%s: symlink support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true"); + return 0; +} + static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid) { uint32_t *p; @@ -1874,6 +1943,22 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint return 0; } +static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) +{ + uint32_t *p; + + *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL; + if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U))) + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) { + READ_BUF(4); + READ32(*res); + bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT; + } + dprintk("%s: ACLs supported=%u\n", __FUNCTION__, (unsigned int)*res); + return 0; +} + static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) { uint32_t *p; @@ -2354,6 +2439,34 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) return 0; } +static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) +{ + uint32_t *savep; + uint32_t attrlen, + bitmap[2] = {0}; + int status; + + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto xdr_error; + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto xdr_error; + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) + goto xdr_error; + if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0) + goto xdr_error; + if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0) + goto xdr_error; + if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0) + goto xdr_error; + if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0) + goto xdr_error; + status = verify_attr_len(xdr, savep, attrlen); +xdr_error: + if (status != 0) + printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status); + return status; +} + static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) { uint32_t *savep; @@ -3475,6 +3588,25 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fss return status; } +/* + * GETATTR_BITMAP request + */ +static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, uint32_t *p, struct nfs4_server_caps_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) + goto out; + if ((status = decode_putfh(&xdr)) != 0) + goto out; + status = decode_server_caps(&xdr, res); +out: + return status; +} + /* * Decode RENEW response */ @@ -3676,6 +3808,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(STATFS, enc_statfs, dec_statfs), PROC(READLINK, enc_readlink, dec_readlink), PROC(READDIR, enc_readdir, dec_readdir), + PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 1befa051b63a..500367d24977 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -47,6 +47,11 @@ #define NFS4_ACE_SYSTEM_AUDIT_ACE_TYPE 2 #define NFS4_ACE_SYSTEM_ALARM_ACE_TYPE 3 +#define ACL4_SUPPORT_ALLOW_ACL 0x01 +#define ACL4_SUPPORT_DENY_ACL 0x02 +#define ACL4_SUPPORT_AUDIT_ACL 0x04 +#define ACL4_SUPPORT_ALARM_ACL 0x08 + typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier; typedef struct { char data[16]; } nfs4_stateid; @@ -314,6 +319,7 @@ enum { NFSPROC4_CLNT_STATFS, NFSPROC4_CLNT_READLINK, NFSPROC4_CLNT_READDIR, + NFSPROC4_CLNT_SERVER_CAPS, }; #endif diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 1b5f7e130502..428355f8aaf9 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -38,10 +38,19 @@ struct nfs_server { struct list_head nfs4_siblings; /* List of other nfs_server structs * that share the same clientid */ + u32 attr_bitmask[2];/* V4 bitmask representing the set + of attributes supported on this + filesystem */ + u32 acl_bitmask; /* V4 bitmask representing the ACEs + that are supported on this + filesystem */ #endif }; /* Server capabilities */ -#define NFS_CAP_READDIRPLUS (1) +#define NFS_CAP_READDIRPLUS (1U << 0) +#define NFS_CAP_HARDLINKS (1U << 1) +#define NFS_CAP_SYMLINKS (1U << 2) +#define NFS_CAP_ACLS (1U << 3) #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 30418767ece3..f47e3c27af27 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -611,6 +611,13 @@ struct nfs4_statfs_arg { const u32 * bitmask; }; +struct nfs4_server_caps_res { + u32 attr_bitmask[2]; + u32 acl_bitmask; + u32 has_links; + u32 has_symlinks; +}; + #endif /* CONFIG_NFS_V4 */ struct nfs_page; -- cgit v1.2.3 From b14d09be66a6fc4b033052daff995923213b0bf7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Apr 2004 21:50:04 -0700 Subject: RPC: Ensure that we only schedule one RPC request at a time. In theory the current code could cause two to be scheduled if something wakes up xprt->snd_task before keventd has had a chance to run xprt_sock_connect() --- include/linux/sunrpc/xprt.h | 7 ++++-- net/sunrpc/xprt.c | 61 +++++++++++++++++++-------------------------- 2 files changed, 31 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 52e4e03016fc..5222a8f4c580 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -216,12 +216,15 @@ void xprt_connect(struct rpc_task *); int xprt_clear_backlog(struct rpc_xprt *); void xprt_sock_setbufsize(struct rpc_xprt *); -#define XPRT_CONNECT 0 -#define XPRT_LOCKED 1 +#define XPRT_LOCKED 0 +#define XPRT_CONNECT 1 +#define XPRT_CONNECTING 2 #define xprt_connected(xp) (test_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_test_and_set_connected(xp) (test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_test_and_clear_connected(xp) \ + (test_and_clear_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_clear_connected(xp) (clear_bit(XPRT_CONNECT, &(xp)->sockstate)) #endif /* __KERNEL__*/ diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 06d7ec9c5fdc..757f39cf1f36 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -448,7 +448,10 @@ xprt_init_autodisconnect(unsigned long data) goto out_abort; spin_unlock(&xprt->sock_lock); /* Let keventd close the socket */ - schedule_work(&xprt->task_cleanup); + if (test_bit(XPRT_CONNECTING, &xprt->sockstate) != 0) + xprt_release_write(xprt, NULL); + else + schedule_work(&xprt->task_cleanup); return; out_abort: spin_unlock(&xprt->sock_lock); @@ -460,12 +463,8 @@ static void xprt_socket_connect(void *args) struct socket *sock = xprt->sock; int status = -EIO; - if (xprt->shutdown) { - rpc_wake_up_status(&xprt->pending, -EIO); - return; - } - if (!xprt->addr.sin_port) - goto out_err; + if (xprt->shutdown || xprt->addr.sin_port == 0) + goto out; /* * Start by resetting any existing state @@ -475,12 +474,12 @@ static void xprt_socket_connect(void *args) if (sock == NULL) { /* couldn't create socket or bind to reserved port; * this is likely a permanent error, so cause an abort */ - goto out_err; - return; + goto out; } xprt_bind_socket(xprt, sock); xprt_sock_setbufsize(xprt); + status = 0; if (!xprt->stream) goto out; @@ -491,29 +490,22 @@ static void xprt_socket_connect(void *args) sizeof(xprt->addr), O_NONBLOCK); dprintk("RPC: %p connect status %d connected %d sock state %d\n", xprt, -status, xprt_connected(xprt), sock->sk->sk_state); - if (status >= 0) - goto out; - switch (status) { - case -EINPROGRESS: - case -EALREADY: - return; - default: - goto out_err; + if (status < 0) { + switch (status) { + case -EINPROGRESS: + case -EALREADY: + goto out_clear; + } } out: - spin_lock_bh(&xprt->sock_lock); - if (xprt->snd_task) - rpc_wake_up_task(xprt->snd_task); - spin_unlock_bh(&xprt->sock_lock); - return; -out_err: - spin_lock_bh(&xprt->sock_lock); - if (xprt->snd_task) { - xprt->snd_task->tk_status = status; - rpc_wake_up_task(xprt->snd_task); - } else - rpc_wake_up_status(&xprt->pending, -ENOTCONN); - spin_unlock_bh(&xprt->sock_lock); + if (status < 0) + rpc_wake_up_status(&xprt->pending, status); + else + rpc_wake_up(&xprt->pending); +out_clear: + smp_mb__before_clear_bit(); + clear_bit(XPRT_CONNECTING, &xprt->sockstate); + smp_mb__after_clear_bit(); } /* @@ -545,7 +537,8 @@ void xprt_connect(struct rpc_task *task) task->tk_timeout = RPC_CONNECT_TIMEOUT; rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); - schedule_work(&xprt->sock_connect); + if (!test_and_set_bit(XPRT_CONNECTING, &xprt->sockstate)) + schedule_work(&xprt->sock_connect); return; out_write: xprt_release_write(xprt, task); @@ -1027,9 +1020,6 @@ tcp_state_change(struct sock *sk) xprt->tcp_reclen = 0; xprt->tcp_copied = 0; xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; - - if (xprt->snd_task) - rpc_wake_up_task(xprt->snd_task); rpc_wake_up(&xprt->pending); } spin_unlock_bh(&xprt->sock_lock); @@ -1038,7 +1028,8 @@ tcp_state_change(struct sock *sk) case TCP_SYN_RECV: break; default: - xprt_disconnect(xprt); + if (xprt_test_and_clear_connected(xprt)) + rpc_wake_up_status(&xprt->pending, -ENOTCONN); break; } out: -- cgit v1.2.3