Blame view
fs/nfs/direct.c
27.6 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 |
/* * linux/fs/nfs/direct.c * * Copyright (C) 2003 by Chuck Lever <cel@netapp.com> * * High-performance uncached I/O for the Linux NFS client * * There are important applications whose performance or correctness * depends on uncached access to file data. Database clusters |
88467055f NFS: clean up com... |
10 |
* (multiple copies of the same instance running on separate hosts) |
1da177e4c Linux-2.6.12-rc2 |
11 |
* implement their own cache coherency protocol that subsumes file |
88467055f NFS: clean up com... |
12 13 14 |
* system cache protocols. Applications that process datasets * considerably larger than the client's memory do not always benefit * from a local cache. A streaming video server, for instance, has no |
1da177e4c Linux-2.6.12-rc2 |
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
* need to cache the contents of a file. * * When an application requests uncached I/O, all read and write requests * are made directly to the server; data stored or fetched via these * requests is not cached in the Linux page cache. The client does not * correct unaligned requests from applications. All requested bytes are * held on permanent storage before a direct write system call returns to * an application. * * Solaris implements an uncached I/O facility called directio() that * is used for backups and sequential I/O to very large files. Solaris * also supports uncaching whole NFS partitions with "-o forcedirectio," * an undocumented mount option. * * Designed by Jeff Kimmel, Chuck Lever, and Trond Myklebust, with * help from Andrew Morton. * * 18 Dec 2001 Initial implementation for 2.4 --cel * 08 Jul 2002 Version for 2.4.19, with bug fixes --trondmy * 08 Jun 2003 Port to 2.5 APIs --cel * 31 Mar 2004 Handle direct I/O without VFS support --cel * 15 Sep 2004 Parallel async reads --cel |
88467055f NFS: clean up com... |
37 |
* 04 May 2005 support O_DIRECT with aio --cel |
1da177e4c Linux-2.6.12-rc2 |
38 39 |
* */ |
1da177e4c Linux-2.6.12-rc2 |
40 41 42 |
#include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
43 44 45 |
#include <linux/file.h> #include <linux/pagemap.h> #include <linux/kref.h> |
5a0e3ad6a include cleanup: ... |
46 |
#include <linux/slab.h> |
7ec10f26e NFS: account dire... |
47 |
#include <linux/task_io_accounting_ops.h> |
1da177e4c Linux-2.6.12-rc2 |
48 49 50 51 52 53 54 |
#include <linux/nfs_fs.h> #include <linux/nfs_page.h> #include <linux/sunrpc/clnt.h> #include <asm/system.h> #include <asm/uaccess.h> |
60063497a atomic: use <linu... |
55 |
#include <linux/atomic.h> |
1da177e4c Linux-2.6.12-rc2 |
56 |
|
8d5658c94 NFS: Fix a buffer... |
57 |
#include "internal.h" |
91d5b4702 NFS: add I/O perf... |
58 |
#include "iostat.h" |
1da177e4c Linux-2.6.12-rc2 |
59 |
#define NFSDBG_FACILITY NFSDBG_VFS |
1da177e4c Linux-2.6.12-rc2 |
60 |
|
e18b890bb [PATCH] slab: rem... |
61 |
static struct kmem_cache *nfs_direct_cachep; |
1da177e4c Linux-2.6.12-rc2 |
62 63 64 65 66 67 |
/* * This represents a set of asynchronous requests that we're waiting on */ struct nfs_direct_req { struct kref kref; /* release manager */ |
15ce4a0c1 NFS: Replace atom... |
68 69 |
/* I/O parameters */ |
a8881f5a5 NFS: O_DIRECT asy... |
70 |
struct nfs_open_context *ctx; /* file open context info */ |
f11ac8db5 NFSv4: Ensure tha... |
71 |
struct nfs_lock_context *l_ctx; /* Lock context info */ |
99514f8fd NFS: make iocb av... |
72 |
struct kiocb * iocb; /* controlling i/o request */ |
88467055f NFS: clean up com... |
73 |
struct inode * inode; /* target file of i/o */ |
15ce4a0c1 NFS: Replace atom... |
74 75 |
/* completion state */ |
607f31e80 Revert "Merge bra... |
76 |
atomic_t io_count; /* i/os we're waiting for */ |
15ce4a0c1 NFS: Replace atom... |
77 |
spinlock_t lock; /* protect completion state */ |
15ce4a0c1 NFS: Replace atom... |
78 |
ssize_t count, /* bytes actually processed */ |
1da177e4c Linux-2.6.12-rc2 |
79 |
error; /* any reported error */ |
d72b7a6b2 NFS: O_DIRECT nee... |
80 |
struct completion completion; /* wait for i/o completion */ |
fad614904 nfs: Use UNSTABLE... |
81 82 |
/* commit state */ |
607f31e80 Revert "Merge bra... |
83 |
struct list_head rewrite_list; /* saved nfs_write_data structs */ |
fad614904 nfs: Use UNSTABLE... |
84 85 86 87 88 |
struct nfs_write_data * commit_data; /* special write_data for commits */ int flags; #define NFS_ODIRECT_DO_COMMIT (1) /* an unstable reply was received */ #define NFS_ODIRECT_RESCHED_WRITES (2) /* write verification failed */ struct nfs_writeverf verf; /* unstable write verifier */ |
1da177e4c Linux-2.6.12-rc2 |
89 |
}; |
fad614904 nfs: Use UNSTABLE... |
90 |
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode); |
607f31e80 Revert "Merge bra... |
91 92 93 94 95 96 97 98 99 100 101 |
static const struct rpc_call_ops nfs_write_direct_ops; static inline void get_dreq(struct nfs_direct_req *dreq) { atomic_inc(&dreq->io_count); } static inline int put_dreq(struct nfs_direct_req *dreq) { return atomic_dec_and_test(&dreq->io_count); } |
1da177e4c Linux-2.6.12-rc2 |
102 |
/** |
b8a32e2b8 NFS: clean up NFS... |
103 104 105 106 107 108 109 110 111 112 113 |
* nfs_direct_IO - NFS address space operation for direct I/O * @rw: direction (read or write) * @iocb: target I/O control block * @iov: array of vectors that define I/O buffer * @pos: offset in file to begin the operation * @nr_segs: size of iovec array * * The presence of this routine in the address space ops vector means * the NFS client supports direct I/O. However, we shunt off direct * read and write requests before the VFS gets them, so this method * should never be called. |
1da177e4c Linux-2.6.12-rc2 |
114 |
*/ |
b8a32e2b8 NFS: clean up NFS... |
115 116 |
ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs) { |
b8a32e2b8 NFS: clean up NFS... |
117 118 |
dprintk("NFS: nfs_direct_IO (%s) off/no(%Ld/%lu) EINVAL ", |
01cce933d [PATCH] nfs: chan... |
119 |
iocb->ki_filp->f_path.dentry->d_name.name, |
e99170ff3 NFS,SUNRPC: Fix c... |
120 |
(long long) pos, nr_segs); |
b8a32e2b8 NFS: clean up NFS... |
121 122 123 |
return -EINVAL; } |
d4a8f3677 NFS: Fix nfs_dire... |
124 |
static void nfs_direct_dirty_pages(struct page **pages, unsigned int pgbase, size_t count) |
6b45d858e NFS: Clean up nfs... |
125 |
{ |
d4a8f3677 NFS: Fix nfs_dire... |
126 |
unsigned int npages; |
749e146e0 NFS: Fix handful ... |
127 |
unsigned int i; |
d4a8f3677 NFS: Fix nfs_dire... |
128 129 130 131 132 |
if (count == 0) return; pages += (pgbase >> PAGE_SHIFT); npages = (count + (pgbase & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; |
6b45d858e NFS: Clean up nfs... |
133 134 |
for (i = 0; i < npages; i++) { struct page *page = pages[i]; |
607f31e80 Revert "Merge bra... |
135 |
if (!PageCompound(page)) |
d4a8f3677 NFS: Fix nfs_dire... |
136 |
set_page_dirty(page); |
6b45d858e NFS: Clean up nfs... |
137 |
} |
9c93ab7df NFS: refactor nfs... |
138 |
} |
749e146e0 NFS: Fix handful ... |
139 |
static void nfs_direct_release_pages(struct page **pages, unsigned int npages) |
9c93ab7df NFS: refactor nfs... |
140 |
{ |
749e146e0 NFS: Fix handful ... |
141 |
unsigned int i; |
607f31e80 Revert "Merge bra... |
142 143 |
for (i = 0; i < npages; i++) page_cache_release(pages[i]); |
6b45d858e NFS: Clean up nfs... |
144 |
} |
93619e598 NFS: create commo... |
145 |
static inline struct nfs_direct_req *nfs_direct_req_alloc(void) |
1da177e4c Linux-2.6.12-rc2 |
146 |
{ |
93619e598 NFS: create commo... |
147 |
struct nfs_direct_req *dreq; |
e94b17660 [PATCH] slab: rem... |
148 |
dreq = kmem_cache_alloc(nfs_direct_cachep, GFP_KERNEL); |
93619e598 NFS: create commo... |
149 150 151 152 |
if (!dreq) return NULL; kref_init(&dreq->kref); |
607f31e80 Revert "Merge bra... |
153 |
kref_get(&dreq->kref); |
d72b7a6b2 NFS: O_DIRECT nee... |
154 |
init_completion(&dreq->completion); |
fad614904 nfs: Use UNSTABLE... |
155 |
INIT_LIST_HEAD(&dreq->rewrite_list); |
93619e598 NFS: create commo... |
156 |
dreq->iocb = NULL; |
a8881f5a5 NFS: O_DIRECT asy... |
157 |
dreq->ctx = NULL; |
f11ac8db5 NFSv4: Ensure tha... |
158 |
dreq->l_ctx = NULL; |
15ce4a0c1 NFS: Replace atom... |
159 |
spin_lock_init(&dreq->lock); |
607f31e80 Revert "Merge bra... |
160 |
atomic_set(&dreq->io_count, 0); |
15ce4a0c1 NFS: Replace atom... |
161 162 |
dreq->count = 0; dreq->error = 0; |
fad614904 nfs: Use UNSTABLE... |
163 |
dreq->flags = 0; |
93619e598 NFS: create commo... |
164 165 |
return dreq; |
1da177e4c Linux-2.6.12-rc2 |
166 |
} |
b4946ffb1 NFS: Fix a refcou... |
167 |
static void nfs_direct_req_free(struct kref *kref) |
1da177e4c Linux-2.6.12-rc2 |
168 169 |
{ struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); |
a8881f5a5 NFS: O_DIRECT asy... |
170 |
|
f11ac8db5 NFSv4: Ensure tha... |
171 172 |
if (dreq->l_ctx != NULL) nfs_put_lock_context(dreq->l_ctx); |
a8881f5a5 NFS: O_DIRECT asy... |
173 174 |
if (dreq->ctx != NULL) put_nfs_open_context(dreq->ctx); |
1da177e4c Linux-2.6.12-rc2 |
175 176 |
kmem_cache_free(nfs_direct_cachep, dreq); } |
b4946ffb1 NFS: Fix a refcou... |
177 178 179 180 |
static void nfs_direct_req_release(struct nfs_direct_req *dreq) { kref_put(&dreq->kref, nfs_direct_req_free); } |
d4cc948ba NFS: update comme... |
181 |
/* |
bc0fb201b NFS: create commo... |
182 183 184 185 |
* Collects and returns the final error value/byte-count. */ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) { |
15ce4a0c1 NFS: Replace atom... |
186 |
ssize_t result = -EIOCBQUEUED; |
bc0fb201b NFS: create commo... |
187 188 189 190 |
/* Async requests don't wait here */ if (dreq->iocb) goto out; |
150030b78 NFS: Switch from ... |
191 |
result = wait_for_completion_killable(&dreq->completion); |
bc0fb201b NFS: create commo... |
192 193 |
if (!result) |
15ce4a0c1 NFS: Replace atom... |
194 |
result = dreq->error; |
bc0fb201b NFS: create commo... |
195 |
if (!result) |
15ce4a0c1 NFS: Replace atom... |
196 |
result = dreq->count; |
bc0fb201b NFS: create commo... |
197 198 |
out: |
bc0fb201b NFS: create commo... |
199 200 201 202 |
return (ssize_t) result; } /* |
607f31e80 Revert "Merge bra... |
203 204 |
* Synchronous I/O uses a stack-allocated iocb. Thus we can't trust * the iocb is still valid here if this is a synchronous request. |
63ab46abc NFS: create commo... |
205 206 207 |
*/ static void nfs_direct_complete(struct nfs_direct_req *dreq) { |
63ab46abc NFS: create commo... |
208 |
if (dreq->iocb) { |
15ce4a0c1 NFS: Replace atom... |
209 |
long res = (long) dreq->error; |
63ab46abc NFS: create commo... |
210 |
if (!res) |
15ce4a0c1 NFS: Replace atom... |
211 |
res = (long) dreq->count; |
63ab46abc NFS: create commo... |
212 |
aio_complete(dreq->iocb, res, 0); |
d72b7a6b2 NFS: O_DIRECT nee... |
213 214 |
} complete_all(&dreq->completion); |
63ab46abc NFS: create commo... |
215 |
|
b4946ffb1 NFS: Fix a refcou... |
216 |
nfs_direct_req_release(dreq); |
63ab46abc NFS: create commo... |
217 218 219 |
} /* |
607f31e80 Revert "Merge bra... |
220 221 222 |
* We must hold a reference to all the pages in this direct read request * until the RPCs complete. This could be long *after* we are woken up in * nfs_direct_wait (for instance, if someone hits ^C on a slow server). |
06cf6f2ed NFS: Eliminate nf... |
223 |
*/ |
ec06c096e NFS: Cleanup of N... |
224 |
static void nfs_direct_read_result(struct rpc_task *task, void *calldata) |
1da177e4c Linux-2.6.12-rc2 |
225 |
{ |
ec06c096e NFS: Cleanup of N... |
226 |
struct nfs_read_data *data = calldata; |
1da177e4c Linux-2.6.12-rc2 |
227 |
|
fdd1e74c8 NFS: Ensure that ... |
228 229 230 231 232 233 234 235 236 |
nfs_readpage_result(task, data); } static void nfs_direct_read_release(void *calldata) { struct nfs_read_data *data = calldata; struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; int status = data->task.tk_status; |
15ce4a0c1 NFS: Replace atom... |
237 238 |
spin_lock(&dreq->lock); |
fdd1e74c8 NFS: Ensure that ... |
239 240 |
if (unlikely(status < 0)) { dreq->error = status; |
d4a8f3677 NFS: Fix nfs_dire... |
241 242 243 244 245 246 247 248 249 |
spin_unlock(&dreq->lock); } else { dreq->count += data->res.count; spin_unlock(&dreq->lock); nfs_direct_dirty_pages(data->pagevec, data->args.pgbase, data->res.count); } nfs_direct_release_pages(data->pagevec, data->npages); |
607f31e80 Revert "Merge bra... |
250 251 252 |
if (put_dreq(dreq)) nfs_direct_complete(dreq); |
1ae88b2e4 NFS: Fix an O_DIR... |
253 |
nfs_readdata_free(data); |
1da177e4c Linux-2.6.12-rc2 |
254 |
} |
ec06c096e NFS: Cleanup of N... |
255 |
static const struct rpc_call_ops nfs_read_direct_ops = { |
f11c88af2 nfs41: read seque... |
256 257 258 |
#if defined(CONFIG_NFS_V4_1) .rpc_call_prepare = nfs_read_prepare, #endif /* CONFIG_NFS_V4_1 */ |
ec06c096e NFS: Cleanup of N... |
259 |
.rpc_call_done = nfs_direct_read_result, |
fdd1e74c8 NFS: Ensure that ... |
260 |
.rpc_release = nfs_direct_read_release, |
ec06c096e NFS: Cleanup of N... |
261 |
}; |
d4cc948ba NFS: update comme... |
262 |
/* |
607f31e80 Revert "Merge bra... |
263 264 265 266 267 |
* For each rsize'd chunk of the user's buffer, dispatch an NFS READ * operation. If nfs_readdata_alloc() or get_user_pages() fails, * bail and stop sending more reads. Read length accounting is * handled automatically by nfs_direct_read_result(). Otherwise, if * no requests have been sent, just return an error. |
1da177e4c Linux-2.6.12-rc2 |
268 |
*/ |
02fe49461 NFS: Clean up new... |
269 270 271 |
static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, const struct iovec *iov, loff_t pos) |
1da177e4c Linux-2.6.12-rc2 |
272 |
{ |
a8881f5a5 NFS: O_DIRECT asy... |
273 |
struct nfs_open_context *ctx = dreq->ctx; |
3d4ff43d8 nfs_open_context ... |
274 |
struct inode *inode = ctx->dentry->d_inode; |
02fe49461 NFS: Clean up new... |
275 276 |
unsigned long user_addr = (unsigned long)iov->iov_base; size_t count = iov->iov_len; |
5dd602f20 NFS: use size_t t... |
277 |
size_t rsize = NFS_SERVER(inode)->rsize; |
077376919 NFS/SUNRPC: Conve... |
278 |
struct rpc_task *task; |
bdc7f021f NFS: Clean up the... |
279 280 281 |
struct rpc_message msg = { .rpc_cred = ctx->cred, }; |
84115e1cd SUNRPC: Cleanup o... |
282 283 |
struct rpc_task_setup task_setup_data = { .rpc_client = NFS_CLIENT(inode), |
bdc7f021f NFS: Clean up the... |
284 |
.rpc_message = &msg, |
84115e1cd SUNRPC: Cleanup o... |
285 |
.callback_ops = &nfs_read_direct_ops, |
101070ca2 NFS: Ensure that ... |
286 |
.workqueue = nfsiod_workqueue, |
84115e1cd SUNRPC: Cleanup o... |
287 288 |
.flags = RPC_TASK_ASYNC, }; |
607f31e80 Revert "Merge bra... |
289 290 291 |
unsigned int pgbase; int result; ssize_t started = 0; |
1da177e4c Linux-2.6.12-rc2 |
292 |
do { |
82b145c5a NFS: alloc nfs_re... |
293 |
struct nfs_read_data *data; |
5dd602f20 NFS: use size_t t... |
294 |
size_t bytes; |
1da177e4c Linux-2.6.12-rc2 |
295 |
|
e9f7bee1d [PATCH] NFS: larg... |
296 297 |
pgbase = user_addr & ~PAGE_MASK; bytes = min(rsize,count); |
607f31e80 Revert "Merge bra... |
298 |
result = -ENOMEM; |
8d5658c94 NFS: Fix a buffer... |
299 |
data = nfs_readdata_alloc(nfs_page_array_len(pgbase, bytes)); |
607f31e80 Revert "Merge bra... |
300 301 |
if (unlikely(!data)) break; |
607f31e80 Revert "Merge bra... |
302 303 304 305 |
down_read(¤t->mm->mmap_sem); result = get_user_pages(current, current->mm, user_addr, data->npages, 1, 0, data->pagevec, NULL); up_read(¤t->mm->mmap_sem); |
749e146e0 NFS: Fix handful ... |
306 |
if (result < 0) { |
1ae88b2e4 NFS: Fix an O_DIR... |
307 |
nfs_readdata_free(data); |
749e146e0 NFS: Fix handful ... |
308 309 310 |
break; } if ((unsigned)result < data->npages) { |
d9df8d6b3 NFS: Don't fail a... |
311 312 313 |
bytes = result * PAGE_SIZE; if (bytes <= pgbase) { nfs_direct_release_pages(data->pagevec, result); |
1ae88b2e4 NFS: Fix an O_DIR... |
314 |
nfs_readdata_free(data); |
d9df8d6b3 NFS: Don't fail a... |
315 316 317 318 |
break; } bytes -= pgbase; data->npages = result; |
607f31e80 Revert "Merge bra... |
319 320 321 |
} get_dreq(dreq); |
82b145c5a NFS: alloc nfs_re... |
322 |
|
607f31e80 Revert "Merge bra... |
323 |
data->req = (struct nfs_page *) dreq; |
1da177e4c Linux-2.6.12-rc2 |
324 |
data->inode = inode; |
bdc7f021f NFS: Clean up the... |
325 |
data->cred = msg.rpc_cred; |
1da177e4c Linux-2.6.12-rc2 |
326 |
data->args.fh = NFS_FH(inode); |
1ae88b2e4 NFS: Fix an O_DIR... |
327 |
data->args.context = ctx; |
f11ac8db5 NFSv4: Ensure tha... |
328 |
data->args.lock_context = dreq->l_ctx; |
88467055f NFS: clean up com... |
329 |
data->args.offset = pos; |
1da177e4c Linux-2.6.12-rc2 |
330 |
data->args.pgbase = pgbase; |
607f31e80 Revert "Merge bra... |
331 |
data->args.pages = data->pagevec; |
1da177e4c Linux-2.6.12-rc2 |
332 333 334 335 |
data->args.count = bytes; data->res.fattr = &data->fattr; data->res.eof = 0; data->res.count = bytes; |
65d269538 NFS: Too many GET... |
336 |
nfs_fattr_init(&data->fattr); |
bdc7f021f NFS: Clean up the... |
337 338 |
msg.rpc_argp = &data->args; msg.rpc_resp = &data->res; |
1da177e4c Linux-2.6.12-rc2 |
339 |
|
077376919 NFS/SUNRPC: Conve... |
340 |
task_setup_data.task = &data->task; |
84115e1cd SUNRPC: Cleanup o... |
341 |
task_setup_data.callback_data = data; |
bdc7f021f NFS: Clean up the... |
342 |
NFS_PROTO(inode)->read_setup(data, &msg); |
1da177e4c Linux-2.6.12-rc2 |
343 |
|
077376919 NFS/SUNRPC: Conve... |
344 |
task = rpc_run_task(&task_setup_data); |
dbae4c73f NFS: Ensure that ... |
345 346 347 |
if (IS_ERR(task)) break; rpc_put_task(task); |
1da177e4c Linux-2.6.12-rc2 |
348 |
|
a3f565b1e NFS: fix print fo... |
349 350 351 |
dprintk("NFS: %5u initiated direct read call " "(req %s/%Ld, %zu bytes @ offset %Lu) ", |
1da177e4c Linux-2.6.12-rc2 |
352 353 354 355 356 |
data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), bytes, (unsigned long long)data->args.offset); |
607f31e80 Revert "Merge bra... |
357 358 |
started += bytes; user_addr += bytes; |
88467055f NFS: clean up com... |
359 |
pos += bytes; |
e9f7bee1d [PATCH] NFS: larg... |
360 |
/* FIXME: Remove this unnecessary math from final patch */ |
1da177e4c Linux-2.6.12-rc2 |
361 |
pgbase += bytes; |
1da177e4c Linux-2.6.12-rc2 |
362 |
pgbase &= ~PAGE_MASK; |
e9f7bee1d [PATCH] NFS: larg... |
363 |
BUG_ON(pgbase != (user_addr & ~PAGE_MASK)); |
1da177e4c Linux-2.6.12-rc2 |
364 365 366 |
count -= bytes; } while (count != 0); |
607f31e80 Revert "Merge bra... |
367 |
|
607f31e80 Revert "Merge bra... |
368 |
if (started) |
c216fd708 NFS: Support mult... |
369 |
return started; |
607f31e80 Revert "Merge bra... |
370 |
return result < 0 ? (ssize_t) result : -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
371 |
} |
19f737879 NFS: Introduce io... |
372 373 374 375 376 377 378 379 380 381 382 383 384 |
static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { ssize_t result = -EINVAL; size_t requested_bytes = 0; unsigned long seg; get_dreq(dreq); for (seg = 0; seg < nr_segs; seg++) { const struct iovec *vec = &iov[seg]; |
02fe49461 NFS: Clean up new... |
385 |
result = nfs_direct_read_schedule_segment(dreq, vec, pos); |
19f737879 NFS: Introduce io... |
386 387 388 389 390 391 392 |
if (result < 0) break; requested_bytes += result; if ((size_t)result < vec->iov_len) break; pos += vec->iov_len; } |
839f7ad69 NFS: Fix "kernel ... |
393 394 395 396 397 398 399 400 |
/* * If no bytes were started, return the error, and let the * generic layer handle the completion. */ if (requested_bytes == 0) { nfs_direct_req_release(dreq); return result < 0 ? result : -EIO; } |
19f737879 NFS: Introduce io... |
401 402 |
if (put_dreq(dreq)) nfs_direct_complete(dreq); |
839f7ad69 NFS: Fix "kernel ... |
403 |
return 0; |
19f737879 NFS: Introduce io... |
404 |
} |
c216fd708 NFS: Support mult... |
405 406 |
static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) |
1da177e4c Linux-2.6.12-rc2 |
407 |
{ |
f11ac8db5 NFSv4: Ensure tha... |
408 |
ssize_t result = -ENOMEM; |
99514f8fd NFS: make iocb av... |
409 |
struct inode *inode = iocb->ki_filp->f_mapping->host; |
1da177e4c Linux-2.6.12-rc2 |
410 |
struct nfs_direct_req *dreq; |
607f31e80 Revert "Merge bra... |
411 |
dreq = nfs_direct_req_alloc(); |
f11ac8db5 NFSv4: Ensure tha... |
412 413 |
if (dreq == NULL) goto out; |
1da177e4c Linux-2.6.12-rc2 |
414 |
|
91d5b4702 NFS: add I/O perf... |
415 |
dreq->inode = inode; |
cd3758e37 NFS: Replace file... |
416 |
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
f11ac8db5 NFSv4: Ensure tha... |
417 418 419 |
dreq->l_ctx = nfs_get_lock_context(dreq->ctx); if (dreq->l_ctx == NULL) goto out_release; |
487b83723 NFS: support EIOC... |
420 421 |
if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; |
1da177e4c Linux-2.6.12-rc2 |
422 |
|
c216fd708 NFS: Support mult... |
423 |
result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); |
607f31e80 Revert "Merge bra... |
424 425 |
if (!result) result = nfs_direct_wait(dreq); |
f11ac8db5 NFSv4: Ensure tha... |
426 |
out_release: |
b4946ffb1 NFS: Fix a refcou... |
427 |
nfs_direct_req_release(dreq); |
f11ac8db5 NFSv4: Ensure tha... |
428 |
out: |
1da177e4c Linux-2.6.12-rc2 |
429 430 |
return result; } |
fad614904 nfs: Use UNSTABLE... |
431 |
static void nfs_direct_free_writedata(struct nfs_direct_req *dreq) |
1da177e4c Linux-2.6.12-rc2 |
432 |
{ |
607f31e80 Revert "Merge bra... |
433 434 |
while (!list_empty(&dreq->rewrite_list)) { struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages); |
fad614904 nfs: Use UNSTABLE... |
435 |
list_del(&data->pages); |
607f31e80 Revert "Merge bra... |
436 |
nfs_direct_release_pages(data->pagevec, data->npages); |
1ae88b2e4 NFS: Fix an O_DIR... |
437 |
nfs_writedata_free(data); |
fad614904 nfs: Use UNSTABLE... |
438 439 |
} } |
1da177e4c Linux-2.6.12-rc2 |
440 |
|
fad614904 nfs: Use UNSTABLE... |
441 442 443 |
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) { |
607f31e80 Revert "Merge bra... |
444 445 446 |
struct inode *inode = dreq->inode; struct list_head *p; struct nfs_write_data *data; |
077376919 NFS/SUNRPC: Conve... |
447 |
struct rpc_task *task; |
bdc7f021f NFS: Clean up the... |
448 449 450 |
struct rpc_message msg = { .rpc_cred = dreq->ctx->cred, }; |
84115e1cd SUNRPC: Cleanup o... |
451 452 |
struct rpc_task_setup task_setup_data = { .rpc_client = NFS_CLIENT(inode), |
a8b40bc7e nfs: Panic when c... |
453 |
.rpc_message = &msg, |
84115e1cd SUNRPC: Cleanup o... |
454 |
.callback_ops = &nfs_write_direct_ops, |
101070ca2 NFS: Ensure that ... |
455 |
.workqueue = nfsiod_workqueue, |
84115e1cd SUNRPC: Cleanup o... |
456 457 |
.flags = RPC_TASK_ASYNC, }; |
1da177e4c Linux-2.6.12-rc2 |
458 |
|
fad614904 nfs: Use UNSTABLE... |
459 |
dreq->count = 0; |
607f31e80 Revert "Merge bra... |
460 461 462 463 464 465 |
get_dreq(dreq); list_for_each(p, &dreq->rewrite_list) { data = list_entry(p, struct nfs_write_data, pages); get_dreq(dreq); |
bdc7f021f NFS: Clean up the... |
466 467 |
/* Use stable writes */ data->args.stable = NFS_FILE_SYNC; |
607f31e80 Revert "Merge bra... |
468 469 470 471 472 473 474 475 476 477 478 |
/* * Reset data->res. */ nfs_fattr_init(&data->fattr); data->res.count = data->args.count; memset(&data->verf, 0, sizeof(data->verf)); /* * Reuse data->task; data->args should not have changed * since the original request was sent. */ |
077376919 NFS/SUNRPC: Conve... |
479 |
task_setup_data.task = &data->task; |
84115e1cd SUNRPC: Cleanup o... |
480 |
task_setup_data.callback_data = data; |
bdc7f021f NFS: Clean up the... |
481 482 483 |
msg.rpc_argp = &data->args; msg.rpc_resp = &data->res; NFS_PROTO(inode)->write_setup(data, &msg); |
607f31e80 Revert "Merge bra... |
484 |
|
607f31e80 Revert "Merge bra... |
485 486 487 |
/* * We're called via an RPC callback, so BKL is already held. */ |
077376919 NFS/SUNRPC: Conve... |
488 489 490 |
task = rpc_run_task(&task_setup_data); if (!IS_ERR(task)) rpc_put_task(task); |
607f31e80 Revert "Merge bra... |
491 492 493 494 495 496 497 498 499 |
dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu) ", data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), data->args.count, (unsigned long long)data->args.offset); } |
fedb595c6 NFS: "open code" ... |
500 |
|
607f31e80 Revert "Merge bra... |
501 502 |
if (put_dreq(dreq)) nfs_direct_write_complete(dreq, inode); |
fad614904 nfs: Use UNSTABLE... |
503 504 505 506 507 |
} static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) { struct nfs_write_data *data = calldata; |
fad614904 nfs: Use UNSTABLE... |
508 509 |
/* Call the NFS version-specific code */ |
c9d8f89d9 NFS: Ensure that ... |
510 511 512 513 514 515 516 517 518 519 |
NFS_PROTO(data->inode)->commit_done(task, data); } static void nfs_direct_commit_release(void *calldata) { struct nfs_write_data *data = calldata; struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; int status = data->task.tk_status; if (status < 0) { |
60fa3f769 NFS: Fix two bugs... |
520 521 |
dprintk("NFS: %5u commit failed with error %d. ", |
c9d8f89d9 NFS: Ensure that ... |
522 |
data->task.tk_pid, status); |
fad614904 nfs: Use UNSTABLE... |
523 |
dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
60fa3f769 NFS: Fix two bugs... |
524 |
} else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { |
c9d8f89d9 NFS: Ensure that ... |
525 526 |
dprintk("NFS: %5u commit verify failed ", data->task.tk_pid); |
fad614904 nfs: Use UNSTABLE... |
527 |
dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
1da177e4c Linux-2.6.12-rc2 |
528 |
} |
c9d8f89d9 NFS: Ensure that ... |
529 530 |
dprintk("NFS: %5u commit returned %d ", data->task.tk_pid, status); |
fad614904 nfs: Use UNSTABLE... |
531 |
nfs_direct_write_complete(dreq, data->inode); |
1ae88b2e4 NFS: Fix an O_DIR... |
532 |
nfs_commit_free(data); |
1da177e4c Linux-2.6.12-rc2 |
533 |
} |
fad614904 nfs: Use UNSTABLE... |
534 |
static const struct rpc_call_ops nfs_commit_direct_ops = { |
21d9a851a nfs41 commit sequ... |
535 536 537 |
#if defined(CONFIG_NFS_V4_1) .rpc_call_prepare = nfs_write_prepare, #endif /* CONFIG_NFS_V4_1 */ |
fad614904 nfs: Use UNSTABLE... |
538 |
.rpc_call_done = nfs_direct_commit_result, |
c9d8f89d9 NFS: Ensure that ... |
539 |
.rpc_release = nfs_direct_commit_release, |
fad614904 nfs: Use UNSTABLE... |
540 541 542 |
}; static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
1da177e4c Linux-2.6.12-rc2 |
543 |
{ |
fad614904 nfs: Use UNSTABLE... |
544 |
struct nfs_write_data *data = dreq->commit_data; |
077376919 NFS/SUNRPC: Conve... |
545 |
struct rpc_task *task; |
bdc7f021f NFS: Clean up the... |
546 547 548 549 550 |
struct rpc_message msg = { .rpc_argp = &data->args, .rpc_resp = &data->res, .rpc_cred = dreq->ctx->cred, }; |
84115e1cd SUNRPC: Cleanup o... |
551 |
struct rpc_task_setup task_setup_data = { |
077376919 NFS/SUNRPC: Conve... |
552 |
.task = &data->task, |
84115e1cd SUNRPC: Cleanup o... |
553 |
.rpc_client = NFS_CLIENT(dreq->inode), |
bdc7f021f NFS: Clean up the... |
554 |
.rpc_message = &msg, |
84115e1cd SUNRPC: Cleanup o... |
555 556 |
.callback_ops = &nfs_commit_direct_ops, .callback_data = data, |
101070ca2 NFS: Ensure that ... |
557 |
.workqueue = nfsiod_workqueue, |
84115e1cd SUNRPC: Cleanup o... |
558 559 |
.flags = RPC_TASK_ASYNC, }; |
1da177e4c Linux-2.6.12-rc2 |
560 |
|
fad614904 nfs: Use UNSTABLE... |
561 |
data->inode = dreq->inode; |
bdc7f021f NFS: Clean up the... |
562 |
data->cred = msg.rpc_cred; |
1da177e4c Linux-2.6.12-rc2 |
563 |
|
fad614904 nfs: Use UNSTABLE... |
564 |
data->args.fh = NFS_FH(data->inode); |
607f31e80 Revert "Merge bra... |
565 566 |
data->args.offset = 0; data->args.count = 0; |
1ae88b2e4 NFS: Fix an O_DIR... |
567 |
data->args.context = dreq->ctx; |
f11ac8db5 NFSv4: Ensure tha... |
568 |
data->args.lock_context = dreq->l_ctx; |
fad614904 nfs: Use UNSTABLE... |
569 570 571 |
data->res.count = 0; data->res.fattr = &data->fattr; data->res.verf = &data->verf; |
65d269538 NFS: Too many GET... |
572 |
nfs_fattr_init(&data->fattr); |
1da177e4c Linux-2.6.12-rc2 |
573 |
|
bdc7f021f NFS: Clean up the... |
574 |
NFS_PROTO(data->inode)->commit_setup(data, &msg); |
1da177e4c Linux-2.6.12-rc2 |
575 |
|
fad614904 nfs: Use UNSTABLE... |
576 577 |
/* Note: task.tk_ops->rpc_release will free dreq->commit_data */ dreq->commit_data = NULL; |
1da177e4c Linux-2.6.12-rc2 |
578 |
|
e99170ff3 NFS,SUNRPC: Fix c... |
579 580 |
dprintk("NFS: %5u initiated commit call ", data->task.tk_pid); |
1da177e4c Linux-2.6.12-rc2 |
581 |
|
077376919 NFS/SUNRPC: Conve... |
582 583 584 |
task = rpc_run_task(&task_setup_data); if (!IS_ERR(task)) rpc_put_task(task); |
fad614904 nfs: Use UNSTABLE... |
585 |
} |
1da177e4c Linux-2.6.12-rc2 |
586 |
|
fad614904 nfs: Use UNSTABLE... |
587 588 589 |
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) { int flags = dreq->flags; |
1da177e4c Linux-2.6.12-rc2 |
590 |
|
fad614904 nfs: Use UNSTABLE... |
591 592 593 594 |
dreq->flags = 0; switch (flags) { case NFS_ODIRECT_DO_COMMIT: nfs_direct_commit_schedule(dreq); |
1da177e4c Linux-2.6.12-rc2 |
595 |
break; |
fad614904 nfs: Use UNSTABLE... |
596 597 598 599 |
case NFS_ODIRECT_RESCHED_WRITES: nfs_direct_write_reschedule(dreq); break; default: |
fad614904 nfs: Use UNSTABLE... |
600 601 602 |
if (dreq->commit_data != NULL) nfs_commit_free(dreq->commit_data); nfs_direct_free_writedata(dreq); |
cd9ae2b6a [PATCH] NFS: Deal... |
603 |
nfs_zap_mapping(inode, inode->i_mapping); |
fad614904 nfs: Use UNSTABLE... |
604 605 606 |
nfs_direct_complete(dreq); } } |
1da177e4c Linux-2.6.12-rc2 |
607 |
|
fad614904 nfs: Use UNSTABLE... |
608 609 |
static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) { |
c9d8f89d9 NFS: Ensure that ... |
610 |
dreq->commit_data = nfs_commitdata_alloc(); |
fad614904 nfs: Use UNSTABLE... |
611 612 613 614 615 616 617 618 |
if (dreq->commit_data != NULL) dreq->commit_data->req = (struct nfs_page *) dreq; } #else static inline void nfs_alloc_commit_data(struct nfs_direct_req *dreq) { dreq->commit_data = NULL; } |
1da177e4c Linux-2.6.12-rc2 |
619 |
|
fad614904 nfs: Use UNSTABLE... |
620 621 |
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) { |
fad614904 nfs: Use UNSTABLE... |
622 |
nfs_direct_free_writedata(dreq); |
cd9ae2b6a [PATCH] NFS: Deal... |
623 |
nfs_zap_mapping(inode, inode->i_mapping); |
fad614904 nfs: Use UNSTABLE... |
624 625 626 |
nfs_direct_complete(dreq); } #endif |
1da177e4c Linux-2.6.12-rc2 |
627 |
|
462d5b329 NFS: make direct ... |
628 |
static void nfs_direct_write_result(struct rpc_task *task, void *calldata) |
1da177e4c Linux-2.6.12-rc2 |
629 |
{ |
462d5b329 NFS: make direct ... |
630 |
struct nfs_write_data *data = calldata; |
462d5b329 NFS: make direct ... |
631 |
|
83762c56c NFS: remove point... |
632 |
nfs_writeback_done(task, data); |
c9d8f89d9 NFS: Ensure that ... |
633 634 635 636 637 638 639 640 641 642 643 |
} /* * NB: Return the value of the first error return code. Subsequent * errors after the first one are ignored. */ static void nfs_direct_write_release(void *calldata) { struct nfs_write_data *data = calldata; struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; int status = data->task.tk_status; |
462d5b329 NFS: make direct ... |
644 |
|
15ce4a0c1 NFS: Replace atom... |
645 |
spin_lock(&dreq->lock); |
1da177e4c Linux-2.6.12-rc2 |
646 |
|
eda3cef8d [PATCH] NFS: Fix ... |
647 |
if (unlikely(status < 0)) { |
432409eeb NFS: Fix for bug ... |
648 |
/* An error has occurred, so we should not commit */ |
60fa3f769 NFS: Fix two bugs... |
649 |
dreq->flags = 0; |
eda3cef8d [PATCH] NFS: Fix ... |
650 |
dreq->error = status; |
eda3cef8d [PATCH] NFS: Fix ... |
651 |
} |
432409eeb NFS: Fix for bug ... |
652 653 |
if (unlikely(dreq->error != 0)) goto out_unlock; |
eda3cef8d [PATCH] NFS: Fix ... |
654 655 |
dreq->count += data->res.count; |
1da177e4c Linux-2.6.12-rc2 |
656 |
|
fad614904 nfs: Use UNSTABLE... |
657 658 659 660 661 |
if (data->res.verf->committed != NFS_FILE_SYNC) { switch (dreq->flags) { case 0: memcpy(&dreq->verf, &data->verf, sizeof(dreq->verf)); dreq->flags = NFS_ODIRECT_DO_COMMIT; |
1da177e4c Linux-2.6.12-rc2 |
662 |
break; |
fad614904 nfs: Use UNSTABLE... |
663 664 |
case NFS_ODIRECT_DO_COMMIT: if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { |
c9d8f89d9 NFS: Ensure that ... |
665 666 |
dprintk("NFS: %5u write verify failed ", data->task.tk_pid); |
fad614904 nfs: Use UNSTABLE... |
667 668 |
dreq->flags = NFS_ODIRECT_RESCHED_WRITES; } |
1da177e4c Linux-2.6.12-rc2 |
669 |
} |
1da177e4c Linux-2.6.12-rc2 |
670 |
} |
eda3cef8d [PATCH] NFS: Fix ... |
671 |
out_unlock: |
fad614904 nfs: Use UNSTABLE... |
672 |
spin_unlock(&dreq->lock); |
1da177e4c Linux-2.6.12-rc2 |
673 |
|
607f31e80 Revert "Merge bra... |
674 675 |
if (put_dreq(dreq)) nfs_direct_write_complete(dreq, data->inode); |
462d5b329 NFS: make direct ... |
676 677 678 |
} static const struct rpc_call_ops nfs_write_direct_ops = { |
def6ed7ef nfs41 write seque... |
679 680 681 |
#if defined(CONFIG_NFS_V4_1) .rpc_call_prepare = nfs_write_prepare, #endif /* CONFIG_NFS_V4_1 */ |
462d5b329 NFS: make direct ... |
682 |
.rpc_call_done = nfs_direct_write_result, |
fad614904 nfs: Use UNSTABLE... |
683 |
.rpc_release = nfs_direct_write_release, |
462d5b329 NFS: make direct ... |
684 685 686 |
}; /* |
607f31e80 Revert "Merge bra... |
687 688 689 690 691 |
* For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE * operation. If nfs_writedata_alloc() or get_user_pages() fails, * bail and stop sending more writes. Write length accounting is * handled automatically by nfs_direct_write_result(). Otherwise, if * no requests have been sent, just return an error. |
462d5b329 NFS: make direct ... |
692 |
*/ |
02fe49461 NFS: Clean up new... |
693 694 695 |
static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, const struct iovec *iov, loff_t pos, int sync) |
462d5b329 NFS: make direct ... |
696 |
{ |
a8881f5a5 NFS: O_DIRECT asy... |
697 |
struct nfs_open_context *ctx = dreq->ctx; |
3d4ff43d8 nfs_open_context ... |
698 |
struct inode *inode = ctx->dentry->d_inode; |
02fe49461 NFS: Clean up new... |
699 700 |
unsigned long user_addr = (unsigned long)iov->iov_base; size_t count = iov->iov_len; |
077376919 NFS/SUNRPC: Conve... |
701 |
struct rpc_task *task; |
bdc7f021f NFS: Clean up the... |
702 703 704 |
struct rpc_message msg = { .rpc_cred = ctx->cred, }; |
84115e1cd SUNRPC: Cleanup o... |
705 706 |
struct rpc_task_setup task_setup_data = { .rpc_client = NFS_CLIENT(inode), |
bdc7f021f NFS: Clean up the... |
707 |
.rpc_message = &msg, |
84115e1cd SUNRPC: Cleanup o... |
708 |
.callback_ops = &nfs_write_direct_ops, |
101070ca2 NFS: Ensure that ... |
709 |
.workqueue = nfsiod_workqueue, |
84115e1cd SUNRPC: Cleanup o... |
710 711 |
.flags = RPC_TASK_ASYNC, }; |
462d5b329 NFS: make direct ... |
712 |
size_t wsize = NFS_SERVER(inode)->wsize; |
607f31e80 Revert "Merge bra... |
713 714 715 |
unsigned int pgbase; int result; ssize_t started = 0; |
82b145c5a NFS: alloc nfs_re... |
716 |
|
1da177e4c Linux-2.6.12-rc2 |
717 |
do { |
82b145c5a NFS: alloc nfs_re... |
718 |
struct nfs_write_data *data; |
462d5b329 NFS: make direct ... |
719 |
size_t bytes; |
e9f7bee1d [PATCH] NFS: larg... |
720 721 |
pgbase = user_addr & ~PAGE_MASK; bytes = min(wsize,count); |
607f31e80 Revert "Merge bra... |
722 |
result = -ENOMEM; |
8d5658c94 NFS: Fix a buffer... |
723 |
data = nfs_writedata_alloc(nfs_page_array_len(pgbase, bytes)); |
607f31e80 Revert "Merge bra... |
724 725 |
if (unlikely(!data)) break; |
607f31e80 Revert "Merge bra... |
726 727 728 729 |
down_read(¤t->mm->mmap_sem); result = get_user_pages(current, current->mm, user_addr, data->npages, 0, 0, data->pagevec, NULL); up_read(¤t->mm->mmap_sem); |
749e146e0 NFS: Fix handful ... |
730 |
if (result < 0) { |
1ae88b2e4 NFS: Fix an O_DIR... |
731 |
nfs_writedata_free(data); |
749e146e0 NFS: Fix handful ... |
732 733 734 |
break; } if ((unsigned)result < data->npages) { |
d9df8d6b3 NFS: Don't fail a... |
735 736 737 |
bytes = result * PAGE_SIZE; if (bytes <= pgbase) { nfs_direct_release_pages(data->pagevec, result); |
1ae88b2e4 NFS: Fix an O_DIR... |
738 |
nfs_writedata_free(data); |
d9df8d6b3 NFS: Don't fail a... |
739 740 741 742 |
break; } bytes -= pgbase; data->npages = result; |
607f31e80 Revert "Merge bra... |
743 744 745 |
} get_dreq(dreq); |
fad614904 nfs: Use UNSTABLE... |
746 |
list_move_tail(&data->pages, &dreq->rewrite_list); |
462d5b329 NFS: make direct ... |
747 |
|
607f31e80 Revert "Merge bra... |
748 |
data->req = (struct nfs_page *) dreq; |
462d5b329 NFS: make direct ... |
749 |
data->inode = inode; |
bdc7f021f NFS: Clean up the... |
750 |
data->cred = msg.rpc_cred; |
462d5b329 NFS: make direct ... |
751 |
data->args.fh = NFS_FH(inode); |
1ae88b2e4 NFS: Fix an O_DIR... |
752 |
data->args.context = ctx; |
f11ac8db5 NFSv4: Ensure tha... |
753 |
data->args.lock_context = dreq->l_ctx; |
88467055f NFS: clean up com... |
754 |
data->args.offset = pos; |
462d5b329 NFS: make direct ... |
755 |
data->args.pgbase = pgbase; |
607f31e80 Revert "Merge bra... |
756 |
data->args.pages = data->pagevec; |
462d5b329 NFS: make direct ... |
757 |
data->args.count = bytes; |
bdc7f021f NFS: Clean up the... |
758 |
data->args.stable = sync; |
462d5b329 NFS: make direct ... |
759 760 |
data->res.fattr = &data->fattr; data->res.count = bytes; |
47989d745 NFS: remove suppo... |
761 |
data->res.verf = &data->verf; |
65d269538 NFS: Too many GET... |
762 |
nfs_fattr_init(&data->fattr); |
462d5b329 NFS: make direct ... |
763 |
|
077376919 NFS/SUNRPC: Conve... |
764 |
task_setup_data.task = &data->task; |
84115e1cd SUNRPC: Cleanup o... |
765 |
task_setup_data.callback_data = data; |
bdc7f021f NFS: Clean up the... |
766 767 768 |
msg.rpc_argp = &data->args; msg.rpc_resp = &data->res; NFS_PROTO(inode)->write_setup(data, &msg); |
1da177e4c Linux-2.6.12-rc2 |
769 |
|
077376919 NFS/SUNRPC: Conve... |
770 |
task = rpc_run_task(&task_setup_data); |
dbae4c73f NFS: Ensure that ... |
771 772 773 |
if (IS_ERR(task)) break; rpc_put_task(task); |
1da177e4c Linux-2.6.12-rc2 |
774 |
|
a3f565b1e NFS: fix print fo... |
775 776 777 |
dprintk("NFS: %5u initiated direct write call " "(req %s/%Ld, %zu bytes @ offset %Lu) ", |
462d5b329 NFS: make direct ... |
778 779 780 781 782 |
data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), bytes, (unsigned long long)data->args.offset); |
1da177e4c Linux-2.6.12-rc2 |
783 |
|
607f31e80 Revert "Merge bra... |
784 785 |
started += bytes; user_addr += bytes; |
88467055f NFS: clean up com... |
786 |
pos += bytes; |
e9f7bee1d [PATCH] NFS: larg... |
787 788 |
/* FIXME: Remove this useless math from the final patch */ |
462d5b329 NFS: make direct ... |
789 |
pgbase += bytes; |
462d5b329 NFS: make direct ... |
790 |
pgbase &= ~PAGE_MASK; |
e9f7bee1d [PATCH] NFS: larg... |
791 |
BUG_ON(pgbase != (user_addr & ~PAGE_MASK)); |
1da177e4c Linux-2.6.12-rc2 |
792 |
|
462d5b329 NFS: make direct ... |
793 794 |
count -= bytes; } while (count != 0); |
607f31e80 Revert "Merge bra... |
795 |
|
607f31e80 Revert "Merge bra... |
796 |
if (started) |
c216fd708 NFS: Support mult... |
797 |
return started; |
607f31e80 Revert "Merge bra... |
798 |
return result < 0 ? (ssize_t) result : -EFAULT; |
462d5b329 NFS: make direct ... |
799 |
} |
1da177e4c Linux-2.6.12-rc2 |
800 |
|
19f737879 NFS: Introduce io... |
801 802 803 804 805 806 807 808 809 810 811 812 813 |
static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, const struct iovec *iov, unsigned long nr_segs, loff_t pos, int sync) { ssize_t result = 0; size_t requested_bytes = 0; unsigned long seg; get_dreq(dreq); for (seg = 0; seg < nr_segs; seg++) { const struct iovec *vec = &iov[seg]; |
02fe49461 NFS: Clean up new... |
814 815 |
result = nfs_direct_write_schedule_segment(dreq, vec, pos, sync); |
19f737879 NFS: Introduce io... |
816 817 818 819 820 821 822 |
if (result < 0) break; requested_bytes += result; if ((size_t)result < vec->iov_len) break; pos += vec->iov_len; } |
839f7ad69 NFS: Fix "kernel ... |
823 824 825 826 827 828 829 830 |
/* * If no bytes were started, return the error, and let the * generic layer handle the completion. */ if (requested_bytes == 0) { nfs_direct_req_release(dreq); return result < 0 ? result : -EIO; } |
19f737879 NFS: Introduce io... |
831 832 |
if (put_dreq(dreq)) nfs_direct_write_complete(dreq, dreq->inode); |
839f7ad69 NFS: Fix "kernel ... |
833 |
return 0; |
19f737879 NFS: Introduce io... |
834 |
} |
c216fd708 NFS: Support mult... |
835 836 837 |
static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos, size_t count) |
462d5b329 NFS: make direct ... |
838 |
{ |
f11ac8db5 NFSv4: Ensure tha... |
839 |
ssize_t result = -ENOMEM; |
c89f2ee5f NFS: make iocb av... |
840 |
struct inode *inode = iocb->ki_filp->f_mapping->host; |
462d5b329 NFS: make direct ... |
841 |
struct nfs_direct_req *dreq; |
fad614904 nfs: Use UNSTABLE... |
842 |
size_t wsize = NFS_SERVER(inode)->wsize; |
bdc7f021f NFS: Clean up the... |
843 |
int sync = NFS_UNSTABLE; |
1da177e4c Linux-2.6.12-rc2 |
844 |
|
607f31e80 Revert "Merge bra... |
845 |
dreq = nfs_direct_req_alloc(); |
462d5b329 NFS: make direct ... |
846 |
if (!dreq) |
f11ac8db5 NFSv4: Ensure tha... |
847 |
goto out; |
607f31e80 Revert "Merge bra... |
848 |
nfs_alloc_commit_data(dreq); |
b47d19de2 Pure nfs client p... |
849 |
if (dreq->commit_data == NULL || count <= wsize) |
bdc7f021f NFS: Clean up the... |
850 |
sync = NFS_FILE_SYNC; |
1da177e4c Linux-2.6.12-rc2 |
851 |
|
c89f2ee5f NFS: make iocb av... |
852 |
dreq->inode = inode; |
cd3758e37 NFS: Replace file... |
853 |
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
f11ac8db5 NFSv4: Ensure tha... |
854 |
dreq->l_ctx = nfs_get_lock_context(dreq->ctx); |
568a810d7 Fixed Regression ... |
855 |
if (dreq->l_ctx == NULL) |
f11ac8db5 NFSv4: Ensure tha... |
856 |
goto out_release; |
c89f2ee5f NFS: make iocb av... |
857 858 |
if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; |
1da177e4c Linux-2.6.12-rc2 |
859 |
|
c216fd708 NFS: Support mult... |
860 |
result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); |
607f31e80 Revert "Merge bra... |
861 862 |
if (!result) result = nfs_direct_wait(dreq); |
f11ac8db5 NFSv4: Ensure tha... |
863 |
out_release: |
b4946ffb1 NFS: Fix a refcou... |
864 |
nfs_direct_req_release(dreq); |
f11ac8db5 NFSv4: Ensure tha... |
865 |
out: |
1da177e4c Linux-2.6.12-rc2 |
866 867 868 869 870 871 |
return result; } /** * nfs_file_direct_read - file direct read operation for NFS files * @iocb: target I/O control block |
027445c37 [PATCH] Vectorize... |
872 873 |
* @iov: vector of user buffers into which to read data * @nr_segs: size of iov vector |
88467055f NFS: clean up com... |
874 |
* @pos: byte offset in file where reading starts |
1da177e4c Linux-2.6.12-rc2 |
875 876 877 878 879 880 |
* * We use this function for direct reads instead of calling * generic_file_aio_read() in order to avoid gfar's check to see if * the request starts before the end of the file. For that check * to work, we must generate a GETATTR before each direct read, and * even then there is a window between the GETATTR and the subsequent |
88467055f NFS: clean up com... |
881 |
* READ where the file size could change. Our preference is simply |
1da177e4c Linux-2.6.12-rc2 |
882 883 |
* to do all reads the application wants, and the server will take * care of managing the end of file boundary. |
88467055f NFS: clean up com... |
884 |
* |
1da177e4c Linux-2.6.12-rc2 |
885 886 887 888 889 |
* This function also eliminates unnecessarily updating the file's * atime locally, as the NFS server sets the file's atime, and this * client must read the updated atime from the server back into its * cache. */ |
027445c37 [PATCH] Vectorize... |
890 891 |
ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) |
1da177e4c Linux-2.6.12-rc2 |
892 893 |
{ ssize_t retval = -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
894 |
struct file *file = iocb->ki_filp; |
1da177e4c Linux-2.6.12-rc2 |
895 |
struct address_space *mapping = file->f_mapping; |
c216fd708 NFS: Support mult... |
896 897 898 899 |
size_t count; count = iov_length(iov, nr_segs); nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); |
1da177e4c Linux-2.6.12-rc2 |
900 |
|
6da24bc9c NFS: Use NFSDBG_F... |
901 902 |
dfprintk(FILE, "NFS: direct read(%s/%s, %zd@%Ld) ", |
01cce933d [PATCH] nfs: chan... |
903 904 |
file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, |
c216fd708 NFS: Support mult... |
905 |
count, (long long) pos); |
1da177e4c Linux-2.6.12-rc2 |
906 |
|
1da177e4c Linux-2.6.12-rc2 |
907 908 909 |
retval = 0; if (!count) goto out; |
29884df0d NFS: Fix another ... |
910 911 912 |
retval = nfs_sync_mapping(mapping); if (retval) goto out; |
1da177e4c Linux-2.6.12-rc2 |
913 |
|
7ec10f26e NFS: account dire... |
914 |
task_io_account_read(count); |
c216fd708 NFS: Support mult... |
915 |
retval = nfs_direct_read(iocb, iov, nr_segs, pos); |
1da177e4c Linux-2.6.12-rc2 |
916 |
if (retval > 0) |
0cdd80d07 NFS: remove suppo... |
917 |
iocb->ki_pos = pos + retval; |
1da177e4c Linux-2.6.12-rc2 |
918 919 920 921 922 923 924 925 |
out: return retval; } /** * nfs_file_direct_write - file direct write operation for NFS files * @iocb: target I/O control block |
027445c37 [PATCH] Vectorize... |
926 927 |
* @iov: vector of user buffers from which to write data * @nr_segs: size of iov vector |
88467055f NFS: clean up com... |
928 |
* @pos: byte offset in file where writing starts |
1da177e4c Linux-2.6.12-rc2 |
929 930 931 932 933 934 935 936 |
* * We use this function for direct writes instead of calling * generic_file_aio_write() in order to avoid taking the inode * semaphore and updating the i_size. The NFS server will set * the new i_size and this client must read the updated size * back into its cache. We let the server do generic write * parameter checking and report problems. * |
1da177e4c Linux-2.6.12-rc2 |
937 938 939 940 941 942 943 944 |
* We eliminate local atime updates, see direct read above. * * We avoid unnecessary page cache invalidations for normal cached * readers of this file. * * Note that O_APPEND is not supported for NFS direct writes, as there * is no atomic O_APPEND write facility in the NFS protocol. */ |
027445c37 [PATCH] Vectorize... |
945 946 |
ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) |
1da177e4c Linux-2.6.12-rc2 |
947 |
{ |
070ea6021 NFS: Clean ups in... |
948 |
ssize_t retval = -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
949 |
struct file *file = iocb->ki_filp; |
1da177e4c Linux-2.6.12-rc2 |
950 |
struct address_space *mapping = file->f_mapping; |
c216fd708 NFS: Support mult... |
951 |
size_t count; |
1da177e4c Linux-2.6.12-rc2 |
952 |
|
c216fd708 NFS: Support mult... |
953 954 |
count = iov_length(iov, nr_segs); nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); |
6da24bc9c NFS: Use NFSDBG_F... |
955 956 |
dfprintk(FILE, "NFS: direct write(%s/%s, %zd@%Ld) ", |
01cce933d [PATCH] nfs: chan... |
957 958 |
file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, |
c216fd708 NFS: Support mult... |
959 |
count, (long long) pos); |
027445c37 [PATCH] Vectorize... |
960 |
|
ce1a8e679 NFS: use generic_... |
961 962 |
retval = generic_write_checks(file, &pos, &count, 0); if (retval) |
1da177e4c Linux-2.6.12-rc2 |
963 |
goto out; |
ce1a8e679 NFS: use generic_... |
964 965 966 |
retval = -EINVAL; if ((ssize_t) count < 0) |
1da177e4c Linux-2.6.12-rc2 |
967 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
968 969 970 |
retval = 0; if (!count) goto out; |
ce1a8e679 NFS: use generic_... |
971 |
|
29884df0d NFS: Fix another ... |
972 973 974 |
retval = nfs_sync_mapping(mapping); if (retval) goto out; |
1da177e4c Linux-2.6.12-rc2 |
975 |
|
7ec10f26e NFS: account dire... |
976 |
task_io_account_write(count); |
c216fd708 NFS: Support mult... |
977 |
retval = nfs_direct_write(iocb, iov, nr_segs, pos, count); |
9eafa8cc5 NFS: support EIOC... |
978 |
|
1da177e4c Linux-2.6.12-rc2 |
979 |
if (retval > 0) |
ce1a8e679 NFS: use generic_... |
980 |
iocb->ki_pos = pos + retval; |
1da177e4c Linux-2.6.12-rc2 |
981 982 983 984 |
out: return retval; } |
88467055f NFS: clean up com... |
985 986 987 988 |
/** * nfs_init_directcache - create a slab cache for nfs_direct_req structures * */ |
f7b422b17 NFS: Split fs/nfs... |
989 |
int __init nfs_init_directcache(void) |
1da177e4c Linux-2.6.12-rc2 |
990 991 992 |
{ nfs_direct_cachep = kmem_cache_create("nfs_direct_cache", sizeof(struct nfs_direct_req), |
fffb60f93 [PATCH] cpuset me... |
993 994 |
0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), |
20c2df83d mm: Remove slab d... |
995 |
NULL); |
1da177e4c Linux-2.6.12-rc2 |
996 997 998 999 1000 |
if (nfs_direct_cachep == NULL) return -ENOMEM; return 0; } |
88467055f NFS: clean up com... |
1001 |
/** |
f7b422b17 NFS: Split fs/nfs... |
1002 |
* nfs_destroy_directcache - destroy the slab cache for nfs_direct_req structures |
88467055f NFS: clean up com... |
1003 1004 |
* */ |
266bee886 [PATCH] fix stati... |
1005 |
void nfs_destroy_directcache(void) |
1da177e4c Linux-2.6.12-rc2 |
1006 |
{ |
1a1d92c10 [PATCH] Really ig... |
1007 |
kmem_cache_destroy(nfs_direct_cachep); |
1da177e4c Linux-2.6.12-rc2 |
1008 |
} |