diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 1013 |
1 files changed, 617 insertions, 396 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e257172d438c..257e4052492e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -33,11 +33,12 @@ | |||
33 | #include <linux/namei.h> | 33 | #include <linux/namei.h> |
34 | #include <linux/mount.h> | 34 | #include <linux/mount.h> |
35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
36 | #include <linux/vmalloc.h> | ||
36 | 37 | ||
37 | #include "nfs4_fs.h" | ||
38 | #include "delegation.h" | 38 | #include "delegation.h" |
39 | #include "iostat.h" | 39 | #include "iostat.h" |
40 | #include "internal.h" | 40 | #include "internal.h" |
41 | #include "fscache.h" | ||
41 | 42 | ||
42 | /* #define NFS_DEBUG_VERBOSE 1 */ | 43 | /* #define NFS_DEBUG_VERBOSE 1 */ |
43 | 44 | ||
@@ -55,6 +56,7 @@ static int nfs_rename(struct inode *, struct dentry *, | |||
55 | struct inode *, struct dentry *); | 56 | struct inode *, struct dentry *); |
56 | static int nfs_fsync_dir(struct file *, int); | 57 | static int nfs_fsync_dir(struct file *, int); |
57 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 58 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
59 | static int nfs_readdir_clear_array(struct page*, gfp_t); | ||
58 | 60 | ||
59 | const struct file_operations nfs_dir_operations = { | 61 | const struct file_operations nfs_dir_operations = { |
60 | .llseek = nfs_llseek_dir, | 62 | .llseek = nfs_llseek_dir, |
@@ -80,6 +82,10 @@ const struct inode_operations nfs_dir_inode_operations = { | |||
80 | .setattr = nfs_setattr, | 82 | .setattr = nfs_setattr, |
81 | }; | 83 | }; |
82 | 84 | ||
85 | const struct address_space_operations nfs_dir_addr_space_ops = { | ||
86 | .releasepage = nfs_readdir_clear_array, | ||
87 | }; | ||
88 | |||
83 | #ifdef CONFIG_NFS_V3 | 89 | #ifdef CONFIG_NFS_V3 |
84 | const struct inode_operations nfs3_dir_inode_operations = { | 90 | const struct inode_operations nfs3_dir_inode_operations = { |
85 | .create = nfs_create, | 91 | .create = nfs_create, |
@@ -104,8 +110,9 @@ const struct inode_operations nfs3_dir_inode_operations = { | |||
104 | #ifdef CONFIG_NFS_V4 | 110 | #ifdef CONFIG_NFS_V4 |
105 | 111 | ||
106 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); | 112 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); |
113 | static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd); | ||
107 | const struct inode_operations nfs4_dir_inode_operations = { | 114 | const struct inode_operations nfs4_dir_inode_operations = { |
108 | .create = nfs_create, | 115 | .create = nfs_open_create, |
109 | .lookup = nfs_atomic_lookup, | 116 | .lookup = nfs_atomic_lookup, |
110 | .link = nfs_link, | 117 | .link = nfs_link, |
111 | .unlink = nfs_unlink, | 118 | .unlink = nfs_unlink, |
@@ -150,51 +157,197 @@ nfs_opendir(struct inode *inode, struct file *filp) | |||
150 | return res; | 157 | return res; |
151 | } | 158 | } |
152 | 159 | ||
153 | typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int); | 160 | struct nfs_cache_array_entry { |
161 | u64 cookie; | ||
162 | u64 ino; | ||
163 | struct qstr string; | ||
164 | }; | ||
165 | |||
166 | struct nfs_cache_array { | ||
167 | unsigned int size; | ||
168 | int eof_index; | ||
169 | u64 last_cookie; | ||
170 | struct nfs_cache_array_entry array[0]; | ||
171 | }; | ||
172 | |||
173 | #define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry)) | ||
174 | |||
175 | typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); | ||
154 | typedef struct { | 176 | typedef struct { |
155 | struct file *file; | 177 | struct file *file; |
156 | struct page *page; | 178 | struct page *page; |
157 | unsigned long page_index; | 179 | unsigned long page_index; |
158 | __be32 *ptr; | ||
159 | u64 *dir_cookie; | 180 | u64 *dir_cookie; |
160 | loff_t current_index; | 181 | loff_t current_index; |
161 | struct nfs_entry *entry; | ||
162 | decode_dirent_t decode; | 182 | decode_dirent_t decode; |
163 | int plus; | 183 | |
164 | unsigned long timestamp; | 184 | unsigned long timestamp; |
165 | unsigned long gencount; | 185 | unsigned long gencount; |
166 | int timestamp_valid; | 186 | unsigned int cache_entry_index; |
187 | unsigned int plus:1; | ||
188 | unsigned int eof:1; | ||
167 | } nfs_readdir_descriptor_t; | 189 | } nfs_readdir_descriptor_t; |
168 | 190 | ||
169 | /* Now we cache directories properly, by stuffing the dirent | 191 | /* |
170 | * data directly in the page cache. | 192 | * The caller is responsible for calling nfs_readdir_release_array(page) |
171 | * | ||
172 | * Inode invalidation due to refresh etc. takes care of | ||
173 | * _everything_, no sloppy entry flushing logic, no extraneous | ||
174 | * copying, network direct to page cache, the way it was meant | ||
175 | * to be. | ||
176 | * | ||
177 | * NOTE: Dirent information verification is done always by the | ||
178 | * page-in of the RPC reply, nowhere else, this simplies | ||
179 | * things substantially. | ||
180 | */ | 193 | */ |
181 | static | 194 | static |
182 | int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | 195 | struct nfs_cache_array *nfs_readdir_get_array(struct page *page) |
196 | { | ||
197 | if (page == NULL) | ||
198 | return ERR_PTR(-EIO); | ||
199 | return (struct nfs_cache_array *)kmap(page); | ||
200 | } | ||
201 | |||
202 | static | ||
203 | void nfs_readdir_release_array(struct page *page) | ||
204 | { | ||
205 | kunmap(page); | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * we are freeing strings created by nfs_add_to_readdir_array() | ||
210 | */ | ||
211 | static | ||
212 | int nfs_readdir_clear_array(struct page *page, gfp_t mask) | ||
213 | { | ||
214 | struct nfs_cache_array *array = nfs_readdir_get_array(page); | ||
215 | int i; | ||
216 | for (i = 0; i < array->size; i++) | ||
217 | kfree(array->array[i].string.name); | ||
218 | nfs_readdir_release_array(page); | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * the caller is responsible for freeing qstr.name | ||
224 | * when called by nfs_readdir_add_to_array, the strings will be freed in | ||
225 | * nfs_clear_readdir_array() | ||
226 | */ | ||
227 | static | ||
228 | int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int len) | ||
229 | { | ||
230 | string->len = len; | ||
231 | string->name = kmemdup(name, len, GFP_KERNEL); | ||
232 | if (string->name == NULL) | ||
233 | return -ENOMEM; | ||
234 | string->hash = full_name_hash(name, len); | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static | ||
239 | int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page) | ||
240 | { | ||
241 | struct nfs_cache_array *array = nfs_readdir_get_array(page); | ||
242 | struct nfs_cache_array_entry *cache_entry; | ||
243 | int ret; | ||
244 | |||
245 | if (IS_ERR(array)) | ||
246 | return PTR_ERR(array); | ||
247 | ret = -EIO; | ||
248 | if (array->size >= MAX_READDIR_ARRAY) | ||
249 | goto out; | ||
250 | |||
251 | cache_entry = &array->array[array->size]; | ||
252 | cache_entry->cookie = entry->prev_cookie; | ||
253 | cache_entry->ino = entry->ino; | ||
254 | ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); | ||
255 | if (ret) | ||
256 | goto out; | ||
257 | array->last_cookie = entry->cookie; | ||
258 | if (entry->eof == 1) | ||
259 | array->eof_index = array->size; | ||
260 | array->size++; | ||
261 | out: | ||
262 | nfs_readdir_release_array(page); | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | static | ||
267 | int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) | ||
268 | { | ||
269 | loff_t diff = desc->file->f_pos - desc->current_index; | ||
270 | unsigned int index; | ||
271 | |||
272 | if (diff < 0) | ||
273 | goto out_eof; | ||
274 | if (diff >= array->size) { | ||
275 | if (array->eof_index > 0) | ||
276 | goto out_eof; | ||
277 | desc->current_index += array->size; | ||
278 | return -EAGAIN; | ||
279 | } | ||
280 | |||
281 | index = (unsigned int)diff; | ||
282 | *desc->dir_cookie = array->array[index].cookie; | ||
283 | desc->cache_entry_index = index; | ||
284 | if (index == array->eof_index) | ||
285 | desc->eof = 1; | ||
286 | return 0; | ||
287 | out_eof: | ||
288 | desc->eof = 1; | ||
289 | return -EBADCOOKIE; | ||
290 | } | ||
291 | |||
292 | static | ||
293 | int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) | ||
294 | { | ||
295 | int i; | ||
296 | int status = -EAGAIN; | ||
297 | |||
298 | for (i = 0; i < array->size; i++) { | ||
299 | if (i == array->eof_index) { | ||
300 | desc->eof = 1; | ||
301 | status = -EBADCOOKIE; | ||
302 | } | ||
303 | if (array->array[i].cookie == *desc->dir_cookie) { | ||
304 | desc->cache_entry_index = i; | ||
305 | status = 0; | ||
306 | break; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | return status; | ||
311 | } | ||
312 | |||
313 | static | ||
314 | int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) | ||
315 | { | ||
316 | struct nfs_cache_array *array; | ||
317 | int status = -EBADCOOKIE; | ||
318 | |||
319 | if (desc->dir_cookie == NULL) | ||
320 | goto out; | ||
321 | |||
322 | array = nfs_readdir_get_array(desc->page); | ||
323 | if (IS_ERR(array)) { | ||
324 | status = PTR_ERR(array); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | if (*desc->dir_cookie == 0) | ||
329 | status = nfs_readdir_search_for_pos(array, desc); | ||
330 | else | ||
331 | status = nfs_readdir_search_for_cookie(array, desc); | ||
332 | |||
333 | nfs_readdir_release_array(desc->page); | ||
334 | out: | ||
335 | return status; | ||
336 | } | ||
337 | |||
338 | /* Fill a page with xdr information before transferring to the cache page */ | ||
339 | static | ||
340 | int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, | ||
341 | struct nfs_entry *entry, struct file *file, struct inode *inode) | ||
183 | { | 342 | { |
184 | struct file *file = desc->file; | ||
185 | struct inode *inode = file->f_path.dentry->d_inode; | ||
186 | struct rpc_cred *cred = nfs_file_cred(file); | 343 | struct rpc_cred *cred = nfs_file_cred(file); |
187 | unsigned long timestamp, gencount; | 344 | unsigned long timestamp, gencount; |
188 | int error; | 345 | int error; |
189 | 346 | ||
190 | dfprintk(DIRCACHE, "NFS: %s: reading cookie %Lu into page %lu\n", | ||
191 | __func__, (long long)desc->entry->cookie, | ||
192 | page->index); | ||
193 | |||
194 | again: | 347 | again: |
195 | timestamp = jiffies; | 348 | timestamp = jiffies; |
196 | gencount = nfs_inc_attr_generation_counter(); | 349 | gencount = nfs_inc_attr_generation_counter(); |
197 | error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, desc->entry->cookie, page, | 350 | error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, pages, |
198 | NFS_SERVER(inode)->dtsize, desc->plus); | 351 | NFS_SERVER(inode)->dtsize, desc->plus); |
199 | if (error < 0) { | 352 | if (error < 0) { |
200 | /* We requested READDIRPLUS, but the server doesn't grok it */ | 353 | /* We requested READDIRPLUS, but the server doesn't grok it */ |
@@ -208,190 +361,292 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | |||
208 | } | 361 | } |
209 | desc->timestamp = timestamp; | 362 | desc->timestamp = timestamp; |
210 | desc->gencount = gencount; | 363 | desc->gencount = gencount; |
211 | desc->timestamp_valid = 1; | 364 | error: |
212 | SetPageUptodate(page); | 365 | return error; |
213 | /* Ensure consistent page alignment of the data. | ||
214 | * Note: assumes we have exclusive access to this mapping either | ||
215 | * through inode->i_mutex or some other mechanism. | ||
216 | */ | ||
217 | if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) { | ||
218 | /* Should never happen */ | ||
219 | nfs_zap_mapping(inode, inode->i_mapping); | ||
220 | } | ||
221 | unlock_page(page); | ||
222 | return 0; | ||
223 | error: | ||
224 | unlock_page(page); | ||
225 | return -EIO; | ||
226 | } | 366 | } |
227 | 367 | ||
228 | static inline | 368 | /* Fill in an entry based on the xdr code stored in desc->page */ |
229 | int dir_decode(nfs_readdir_descriptor_t *desc) | 369 | static |
370 | int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct xdr_stream *stream) | ||
230 | { | 371 | { |
231 | __be32 *p = desc->ptr; | 372 | __be32 *p = desc->decode(stream, entry, NFS_SERVER(desc->file->f_path.dentry->d_inode), desc->plus); |
232 | p = desc->decode(p, desc->entry, desc->plus); | ||
233 | if (IS_ERR(p)) | 373 | if (IS_ERR(p)) |
234 | return PTR_ERR(p); | 374 | return PTR_ERR(p); |
235 | desc->ptr = p; | 375 | |
236 | if (desc->timestamp_valid) { | 376 | entry->fattr->time_start = desc->timestamp; |
237 | desc->entry->fattr->time_start = desc->timestamp; | 377 | entry->fattr->gencount = desc->gencount; |
238 | desc->entry->fattr->gencount = desc->gencount; | ||
239 | } else | ||
240 | desc->entry->fattr->valid &= ~NFS_ATTR_FATTR; | ||
241 | return 0; | 378 | return 0; |
242 | } | 379 | } |
243 | 380 | ||
244 | static inline | 381 | static |
245 | void dir_page_release(nfs_readdir_descriptor_t *desc) | 382 | int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) |
246 | { | 383 | { |
247 | kunmap(desc->page); | 384 | struct nfs_inode *node; |
248 | page_cache_release(desc->page); | 385 | if (dentry->d_inode == NULL) |
249 | desc->page = NULL; | 386 | goto different; |
250 | desc->ptr = NULL; | 387 | node = NFS_I(dentry->d_inode); |
388 | if (node->fh.size != entry->fh->size) | ||
389 | goto different; | ||
390 | if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0) | ||
391 | goto different; | ||
392 | return 1; | ||
393 | different: | ||
394 | return 0; | ||
251 | } | 395 | } |
252 | 396 | ||
253 | /* | 397 | static |
254 | * Given a pointer to a buffer that has already been filled by a call | 398 | void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) |
255 | * to readdir, find the next entry with cookie '*desc->dir_cookie'. | ||
256 | * | ||
257 | * If the end of the buffer has been reached, return -EAGAIN, if not, | ||
258 | * return the offset within the buffer of the next entry to be | ||
259 | * read. | ||
260 | */ | ||
261 | static inline | ||
262 | int find_dirent(nfs_readdir_descriptor_t *desc) | ||
263 | { | 399 | { |
264 | struct nfs_entry *entry = desc->entry; | 400 | struct qstr filename = { |
265 | int loop_count = 0, | 401 | .len = entry->len, |
266 | status; | 402 | .name = entry->name, |
403 | }; | ||
404 | struct dentry *dentry; | ||
405 | struct dentry *alias; | ||
406 | struct inode *dir = parent->d_inode; | ||
407 | struct inode *inode; | ||
267 | 408 | ||
268 | while((status = dir_decode(desc)) == 0) { | 409 | if (filename.name[0] == '.') { |
269 | dfprintk(DIRCACHE, "NFS: %s: examining cookie %Lu\n", | 410 | if (filename.len == 1) |
270 | __func__, (unsigned long long)entry->cookie); | 411 | return; |
271 | if (entry->prev_cookie == *desc->dir_cookie) | 412 | if (filename.len == 2 && filename.name[1] == '.') |
272 | break; | 413 | return; |
273 | if (loop_count++ > 200) { | 414 | } |
274 | loop_count = 0; | 415 | filename.hash = full_name_hash(filename.name, filename.len); |
275 | schedule(); | 416 | |
417 | dentry = d_lookup(parent, &filename); | ||
418 | if (dentry != NULL) { | ||
419 | if (nfs_same_file(dentry, entry)) { | ||
420 | nfs_refresh_inode(dentry->d_inode, entry->fattr); | ||
421 | goto out; | ||
422 | } else { | ||
423 | d_drop(dentry); | ||
424 | dput(dentry); | ||
276 | } | 425 | } |
277 | } | 426 | } |
278 | return status; | 427 | |
428 | dentry = d_alloc(parent, &filename); | ||
429 | if (dentry == NULL) | ||
430 | return; | ||
431 | |||
432 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | ||
433 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); | ||
434 | if (IS_ERR(inode)) | ||
435 | goto out; | ||
436 | |||
437 | alias = d_materialise_unique(dentry, inode); | ||
438 | if (IS_ERR(alias)) | ||
439 | goto out; | ||
440 | else if (alias) { | ||
441 | nfs_set_verifier(alias, nfs_save_change_attribute(dir)); | ||
442 | dput(alias); | ||
443 | } else | ||
444 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
445 | |||
446 | out: | ||
447 | dput(dentry); | ||
448 | } | ||
449 | |||
450 | /* Perform conversion from xdr to cache array */ | ||
451 | static | ||
452 | void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, | ||
453 | void *xdr_page, struct page *page, unsigned int buflen) | ||
454 | { | ||
455 | struct xdr_stream stream; | ||
456 | struct xdr_buf buf; | ||
457 | __be32 *ptr = xdr_page; | ||
458 | int status; | ||
459 | struct nfs_cache_array *array; | ||
460 | |||
461 | buf.head->iov_base = xdr_page; | ||
462 | buf.head->iov_len = buflen; | ||
463 | buf.tail->iov_len = 0; | ||
464 | buf.page_base = 0; | ||
465 | buf.page_len = 0; | ||
466 | buf.buflen = buf.head->iov_len; | ||
467 | buf.len = buf.head->iov_len; | ||
468 | |||
469 | xdr_init_decode(&stream, &buf, ptr); | ||
470 | |||
471 | |||
472 | do { | ||
473 | status = xdr_decode(desc, entry, &stream); | ||
474 | if (status != 0) | ||
475 | break; | ||
476 | |||
477 | if (nfs_readdir_add_to_array(entry, page) == -1) | ||
478 | break; | ||
479 | if (desc->plus == 1) | ||
480 | nfs_prime_dcache(desc->file->f_path.dentry, entry); | ||
481 | } while (!entry->eof); | ||
482 | |||
483 | if (status == -EBADCOOKIE && entry->eof) { | ||
484 | array = nfs_readdir_get_array(page); | ||
485 | array->eof_index = array->size - 1; | ||
486 | status = 0; | ||
487 | nfs_readdir_release_array(page); | ||
488 | } | ||
489 | } | ||
490 | |||
491 | static | ||
492 | void nfs_readdir_free_pagearray(struct page **pages, unsigned int npages) | ||
493 | { | ||
494 | unsigned int i; | ||
495 | for (i = 0; i < npages; i++) | ||
496 | put_page(pages[i]); | ||
497 | } | ||
498 | |||
499 | static | ||
500 | void nfs_readdir_free_large_page(void *ptr, struct page **pages, | ||
501 | unsigned int npages) | ||
502 | { | ||
503 | vm_unmap_ram(ptr, npages); | ||
504 | nfs_readdir_free_pagearray(pages, npages); | ||
279 | } | 505 | } |
280 | 506 | ||
281 | /* | 507 | /* |
282 | * Given a pointer to a buffer that has already been filled by a call | 508 | * nfs_readdir_large_page will allocate pages that must be freed with a call |
283 | * to readdir, find the entry at offset 'desc->file->f_pos'. | 509 | * to nfs_readdir_free_large_page |
284 | * | ||
285 | * If the end of the buffer has been reached, return -EAGAIN, if not, | ||
286 | * return the offset within the buffer of the next entry to be | ||
287 | * read. | ||
288 | */ | 510 | */ |
289 | static inline | 511 | static |
290 | int find_dirent_index(nfs_readdir_descriptor_t *desc) | 512 | void *nfs_readdir_large_page(struct page **pages, unsigned int npages) |
291 | { | 513 | { |
292 | struct nfs_entry *entry = desc->entry; | 514 | void *ptr; |
293 | int loop_count = 0, | 515 | unsigned int i; |
294 | status; | 516 | |
517 | for (i = 0; i < npages; i++) { | ||
518 | struct page *page = alloc_page(GFP_KERNEL); | ||
519 | if (page == NULL) | ||
520 | goto out_freepages; | ||
521 | pages[i] = page; | ||
522 | } | ||
295 | 523 | ||
296 | for(;;) { | 524 | ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL); |
297 | status = dir_decode(desc); | 525 | if (!IS_ERR_OR_NULL(ptr)) |
298 | if (status) | 526 | return ptr; |
299 | break; | 527 | out_freepages: |
528 | nfs_readdir_free_pagearray(pages, i); | ||
529 | return NULL; | ||
530 | } | ||
531 | |||
532 | static | ||
533 | int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode) | ||
534 | { | ||
535 | struct page *pages[NFS_MAX_READDIR_PAGES]; | ||
536 | void *pages_ptr = NULL; | ||
537 | struct nfs_entry entry; | ||
538 | struct file *file = desc->file; | ||
539 | struct nfs_cache_array *array; | ||
540 | int status = 0; | ||
541 | unsigned int array_size = ARRAY_SIZE(pages); | ||
542 | |||
543 | entry.prev_cookie = 0; | ||
544 | entry.cookie = *desc->dir_cookie; | ||
545 | entry.eof = 0; | ||
546 | entry.fh = nfs_alloc_fhandle(); | ||
547 | entry.fattr = nfs_alloc_fattr(); | ||
548 | if (entry.fh == NULL || entry.fattr == NULL) | ||
549 | goto out; | ||
300 | 550 | ||
301 | dfprintk(DIRCACHE, "NFS: found cookie %Lu at index %Ld\n", | 551 | array = nfs_readdir_get_array(page); |
302 | (unsigned long long)entry->cookie, desc->current_index); | 552 | memset(array, 0, sizeof(struct nfs_cache_array)); |
553 | array->eof_index = -1; | ||
303 | 554 | ||
304 | if (desc->file->f_pos == desc->current_index) { | 555 | pages_ptr = nfs_readdir_large_page(pages, array_size); |
305 | *desc->dir_cookie = entry->cookie; | 556 | if (!pages_ptr) |
557 | goto out_release_array; | ||
558 | do { | ||
559 | status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode); | ||
560 | |||
561 | if (status < 0) | ||
306 | break; | 562 | break; |
307 | } | 563 | nfs_readdir_page_filler(desc, &entry, pages_ptr, page, array_size * PAGE_SIZE); |
308 | desc->current_index++; | 564 | } while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY); |
309 | if (loop_count++ > 200) { | 565 | |
310 | loop_count = 0; | 566 | nfs_readdir_free_large_page(pages_ptr, pages, array_size); |
311 | schedule(); | 567 | out_release_array: |
312 | } | 568 | nfs_readdir_release_array(page); |
313 | } | 569 | out: |
570 | nfs_free_fattr(entry.fattr); | ||
571 | nfs_free_fhandle(entry.fh); | ||
314 | return status; | 572 | return status; |
315 | } | 573 | } |
316 | 574 | ||
317 | /* | 575 | /* |
318 | * Find the given page, and call find_dirent() or find_dirent_index in | 576 | * Now we cache directories properly, by converting xdr information |
319 | * order to try to return the next entry. | 577 | * to an array that can be used for lookups later. This results in |
578 | * fewer cache pages, since we can store more information on each page. | ||
579 | * We only need to convert from xdr once so future lookups are much simpler | ||
320 | */ | 580 | */ |
321 | static inline | 581 | static |
322 | int find_dirent_page(nfs_readdir_descriptor_t *desc) | 582 | int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) |
323 | { | 583 | { |
324 | struct inode *inode = desc->file->f_path.dentry->d_inode; | 584 | struct inode *inode = desc->file->f_path.dentry->d_inode; |
325 | struct page *page; | ||
326 | int status; | ||
327 | 585 | ||
328 | dfprintk(DIRCACHE, "NFS: %s: searching page %ld for target %Lu\n", | 586 | if (nfs_readdir_xdr_to_array(desc, page, inode) < 0) |
329 | __func__, desc->page_index, | 587 | goto error; |
330 | (long long) *desc->dir_cookie); | 588 | SetPageUptodate(page); |
331 | 589 | ||
332 | /* If we find the page in the page_cache, we cannot be sure | 590 | if (invalidate_inode_pages2_range(inode->i_mapping, page->index + 1, -1) < 0) { |
333 | * how fresh the data is, so we will ignore readdir_plus attributes. | 591 | /* Should never happen */ |
334 | */ | 592 | nfs_zap_mapping(inode, inode->i_mapping); |
335 | desc->timestamp_valid = 0; | ||
336 | page = read_cache_page(inode->i_mapping, desc->page_index, | ||
337 | (filler_t *)nfs_readdir_filler, desc); | ||
338 | if (IS_ERR(page)) { | ||
339 | status = PTR_ERR(page); | ||
340 | goto out; | ||
341 | } | 593 | } |
594 | unlock_page(page); | ||
595 | return 0; | ||
596 | error: | ||
597 | unlock_page(page); | ||
598 | return -EIO; | ||
599 | } | ||
342 | 600 | ||
343 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ | 601 | static |
344 | desc->page = page; | 602 | void cache_page_release(nfs_readdir_descriptor_t *desc) |
345 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 603 | { |
346 | if (*desc->dir_cookie != 0) | 604 | page_cache_release(desc->page); |
347 | status = find_dirent(desc); | 605 | desc->page = NULL; |
348 | else | 606 | } |
349 | status = find_dirent_index(desc); | 607 | |
350 | if (status < 0) | 608 | static |
351 | dir_page_release(desc); | 609 | struct page *get_cache_page(nfs_readdir_descriptor_t *desc) |
352 | out: | 610 | { |
353 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, status); | 611 | struct page *page; |
354 | return status; | 612 | page = read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping, |
613 | desc->page_index, (filler_t *)nfs_readdir_filler, desc); | ||
614 | if (IS_ERR(page)) | ||
615 | desc->eof = 1; | ||
616 | return page; | ||
355 | } | 617 | } |
356 | 618 | ||
357 | /* | 619 | /* |
358 | * Recurse through the page cache pages, and return a | 620 | * Returns 0 if desc->dir_cookie was found on page desc->page_index |
359 | * filled nfs_entry structure of the next directory entry if possible. | ||
360 | * | ||
361 | * The target for the search is '*desc->dir_cookie' if non-0, | ||
362 | * 'desc->file->f_pos' otherwise | ||
363 | */ | 621 | */ |
622 | static | ||
623 | int find_cache_page(nfs_readdir_descriptor_t *desc) | ||
624 | { | ||
625 | int res; | ||
626 | |||
627 | desc->page = get_cache_page(desc); | ||
628 | if (IS_ERR(desc->page)) | ||
629 | return PTR_ERR(desc->page); | ||
630 | |||
631 | res = nfs_readdir_search_array(desc); | ||
632 | if (res == 0) | ||
633 | return 0; | ||
634 | cache_page_release(desc); | ||
635 | return res; | ||
636 | } | ||
637 | |||
638 | /* Search for desc->dir_cookie from the beginning of the page cache */ | ||
364 | static inline | 639 | static inline |
365 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | 640 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) |
366 | { | 641 | { |
367 | int loop_count = 0; | 642 | int res = -EAGAIN; |
368 | int res; | ||
369 | |||
370 | /* Always search-by-index from the beginning of the cache */ | ||
371 | if (*desc->dir_cookie == 0) { | ||
372 | dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for offset %Ld\n", | ||
373 | (long long)desc->file->f_pos); | ||
374 | desc->page_index = 0; | ||
375 | desc->entry->cookie = desc->entry->prev_cookie = 0; | ||
376 | desc->entry->eof = 0; | ||
377 | desc->current_index = 0; | ||
378 | } else | ||
379 | dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", | ||
380 | (unsigned long long)*desc->dir_cookie); | ||
381 | 643 | ||
382 | for (;;) { | 644 | while (1) { |
383 | res = find_dirent_page(desc); | 645 | res = find_cache_page(desc); |
384 | if (res != -EAGAIN) | 646 | if (res != -EAGAIN) |
385 | break; | 647 | break; |
386 | /* Align to beginning of next page */ | 648 | desc->page_index++; |
387 | desc->page_index ++; | ||
388 | if (loop_count++ > 200) { | ||
389 | loop_count = 0; | ||
390 | schedule(); | ||
391 | } | ||
392 | } | 649 | } |
393 | |||
394 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, res); | ||
395 | return res; | 650 | return res; |
396 | } | 651 | } |
397 | 652 | ||
@@ -400,8 +655,6 @@ static inline unsigned int dt_type(struct inode *inode) | |||
400 | return (inode->i_mode >> 12) & 15; | 655 | return (inode->i_mode >> 12) & 15; |
401 | } | 656 | } |
402 | 657 | ||
403 | static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc); | ||
404 | |||
405 | /* | 658 | /* |
406 | * Once we've found the start of the dirent within a page: fill 'er up... | 659 | * Once we've found the start of the dirent within a page: fill 'er up... |
407 | */ | 660 | */ |
@@ -410,49 +663,36 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
410 | filldir_t filldir) | 663 | filldir_t filldir) |
411 | { | 664 | { |
412 | struct file *file = desc->file; | 665 | struct file *file = desc->file; |
413 | struct nfs_entry *entry = desc->entry; | 666 | int i = 0; |
414 | struct dentry *dentry = NULL; | 667 | int res = 0; |
415 | u64 fileid; | 668 | struct nfs_cache_array *array = NULL; |
416 | int loop_count = 0, | 669 | unsigned int d_type = DT_UNKNOWN; |
417 | res; | 670 | struct dentry *dentry = NULL; |
418 | |||
419 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", | ||
420 | (unsigned long long)entry->cookie); | ||
421 | |||
422 | for(;;) { | ||
423 | unsigned d_type = DT_UNKNOWN; | ||
424 | /* Note: entry->prev_cookie contains the cookie for | ||
425 | * retrieving the current dirent on the server */ | ||
426 | fileid = entry->ino; | ||
427 | |||
428 | /* Get a dentry if we have one */ | ||
429 | if (dentry != NULL) | ||
430 | dput(dentry); | ||
431 | dentry = nfs_readdir_lookup(desc); | ||
432 | 671 | ||
433 | /* Use readdirplus info */ | 672 | array = nfs_readdir_get_array(desc->page); |
434 | if (dentry != NULL && dentry->d_inode != NULL) { | ||
435 | d_type = dt_type(dentry->d_inode); | ||
436 | fileid = NFS_FILEID(dentry->d_inode); | ||
437 | } | ||
438 | 673 | ||
439 | res = filldir(dirent, entry->name, entry->len, | 674 | for (i = desc->cache_entry_index; i < array->size; i++) { |
440 | file->f_pos, nfs_compat_user_ino64(fileid), | 675 | d_type = DT_UNKNOWN; |
441 | d_type); | 676 | |
677 | res = filldir(dirent, array->array[i].string.name, | ||
678 | array->array[i].string.len, file->f_pos, | ||
679 | nfs_compat_user_ino64(array->array[i].ino), d_type); | ||
442 | if (res < 0) | 680 | if (res < 0) |
443 | break; | 681 | break; |
444 | file->f_pos++; | 682 | file->f_pos++; |
445 | *desc->dir_cookie = entry->cookie; | 683 | desc->cache_entry_index = i; |
446 | if (dir_decode(desc) != 0) { | 684 | if (i < (array->size-1)) |
447 | desc->page_index ++; | 685 | *desc->dir_cookie = array->array[i+1].cookie; |
686 | else | ||
687 | *desc->dir_cookie = array->last_cookie; | ||
688 | if (i == array->eof_index) { | ||
689 | desc->eof = 1; | ||
448 | break; | 690 | break; |
449 | } | 691 | } |
450 | if (loop_count++ > 200) { | ||
451 | loop_count = 0; | ||
452 | schedule(); | ||
453 | } | ||
454 | } | 692 | } |
455 | dir_page_release(desc); | 693 | |
694 | nfs_readdir_release_array(desc->page); | ||
695 | cache_page_release(desc); | ||
456 | if (dentry != NULL) | 696 | if (dentry != NULL) |
457 | dput(dentry); | 697 | dput(dentry); |
458 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", | 698 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", |
@@ -476,12 +716,9 @@ static inline | |||
476 | int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | 716 | int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, |
477 | filldir_t filldir) | 717 | filldir_t filldir) |
478 | { | 718 | { |
479 | struct file *file = desc->file; | ||
480 | struct inode *inode = file->f_path.dentry->d_inode; | ||
481 | struct rpc_cred *cred = nfs_file_cred(file); | ||
482 | struct page *page = NULL; | 719 | struct page *page = NULL; |
483 | int status; | 720 | int status; |
484 | unsigned long timestamp, gencount; | 721 | struct inode *inode = desc->file->f_path.dentry->d_inode; |
485 | 722 | ||
486 | dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n", | 723 | dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n", |
487 | (unsigned long long)*desc->dir_cookie); | 724 | (unsigned long long)*desc->dir_cookie); |
@@ -491,38 +728,22 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
491 | status = -ENOMEM; | 728 | status = -ENOMEM; |
492 | goto out; | 729 | goto out; |
493 | } | 730 | } |
494 | timestamp = jiffies; | 731 | |
495 | gencount = nfs_inc_attr_generation_counter(); | 732 | if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) { |
496 | status = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, | ||
497 | *desc->dir_cookie, page, | ||
498 | NFS_SERVER(inode)->dtsize, | ||
499 | desc->plus); | ||
500 | desc->page = page; | ||
501 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | ||
502 | if (status >= 0) { | ||
503 | desc->timestamp = timestamp; | ||
504 | desc->gencount = gencount; | ||
505 | desc->timestamp_valid = 1; | ||
506 | if ((status = dir_decode(desc)) == 0) | ||
507 | desc->entry->prev_cookie = *desc->dir_cookie; | ||
508 | } else | ||
509 | status = -EIO; | 733 | status = -EIO; |
510 | if (status < 0) | ||
511 | goto out_release; | 734 | goto out_release; |
735 | } | ||
512 | 736 | ||
737 | desc->page_index = 0; | ||
738 | desc->page = page; | ||
513 | status = nfs_do_filldir(desc, dirent, filldir); | 739 | status = nfs_do_filldir(desc, dirent, filldir); |
514 | 740 | ||
515 | /* Reset read descriptor so it searches the page cache from | ||
516 | * the start upon the next call to readdir_search_pagecache() */ | ||
517 | desc->page_index = 0; | ||
518 | desc->entry->cookie = desc->entry->prev_cookie = 0; | ||
519 | desc->entry->eof = 0; | ||
520 | out: | 741 | out: |
521 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", | 742 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", |
522 | __func__, status); | 743 | __func__, status); |
523 | return status; | 744 | return status; |
524 | out_release: | 745 | out_release: |
525 | dir_page_release(desc); | 746 | cache_page_release(desc); |
526 | goto out; | 747 | goto out; |
527 | } | 748 | } |
528 | 749 | ||
@@ -536,7 +757,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
536 | struct inode *inode = dentry->d_inode; | 757 | struct inode *inode = dentry->d_inode; |
537 | nfs_readdir_descriptor_t my_desc, | 758 | nfs_readdir_descriptor_t my_desc, |
538 | *desc = &my_desc; | 759 | *desc = &my_desc; |
539 | struct nfs_entry my_entry; | ||
540 | int res = -ENOMEM; | 760 | int res = -ENOMEM; |
541 | 761 | ||
542 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 762 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
@@ -557,26 +777,17 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
557 | desc->decode = NFS_PROTO(inode)->decode_dirent; | 777 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
558 | desc->plus = NFS_USE_READDIRPLUS(inode); | 778 | desc->plus = NFS_USE_READDIRPLUS(inode); |
559 | 779 | ||
560 | my_entry.cookie = my_entry.prev_cookie = 0; | ||
561 | my_entry.eof = 0; | ||
562 | my_entry.fh = nfs_alloc_fhandle(); | ||
563 | my_entry.fattr = nfs_alloc_fattr(); | ||
564 | if (my_entry.fh == NULL || my_entry.fattr == NULL) | ||
565 | goto out_alloc_failed; | ||
566 | |||
567 | desc->entry = &my_entry; | ||
568 | |||
569 | nfs_block_sillyrename(dentry); | 780 | nfs_block_sillyrename(dentry); |
570 | res = nfs_revalidate_mapping(inode, filp->f_mapping); | 781 | res = nfs_revalidate_mapping(inode, filp->f_mapping); |
571 | if (res < 0) | 782 | if (res < 0) |
572 | goto out; | 783 | goto out; |
573 | 784 | ||
574 | while(!desc->entry->eof) { | 785 | while (desc->eof != 1) { |
575 | res = readdir_search_pagecache(desc); | 786 | res = readdir_search_pagecache(desc); |
576 | 787 | ||
577 | if (res == -EBADCOOKIE) { | 788 | if (res == -EBADCOOKIE) { |
578 | /* This means either end of directory */ | 789 | /* This means either end of directory */ |
579 | if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) { | 790 | if (*desc->dir_cookie && desc->eof == 0) { |
580 | /* Or that the server has 'lost' a cookie */ | 791 | /* Or that the server has 'lost' a cookie */ |
581 | res = uncached_readdir(desc, dirent, filldir); | 792 | res = uncached_readdir(desc, dirent, filldir); |
582 | if (res >= 0) | 793 | if (res >= 0) |
@@ -588,8 +799,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
588 | if (res == -ETOOSMALL && desc->plus) { | 799 | if (res == -ETOOSMALL && desc->plus) { |
589 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); | 800 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
590 | nfs_zap_caches(inode); | 801 | nfs_zap_caches(inode); |
802 | desc->page_index = 0; | ||
591 | desc->plus = 0; | 803 | desc->plus = 0; |
592 | desc->entry->eof = 0; | 804 | desc->eof = 0; |
593 | continue; | 805 | continue; |
594 | } | 806 | } |
595 | if (res < 0) | 807 | if (res < 0) |
@@ -605,9 +817,6 @@ out: | |||
605 | nfs_unblock_sillyrename(dentry); | 817 | nfs_unblock_sillyrename(dentry); |
606 | if (res > 0) | 818 | if (res > 0) |
607 | res = 0; | 819 | res = 0; |
608 | out_alloc_failed: | ||
609 | nfs_free_fattr(my_entry.fattr); | ||
610 | nfs_free_fhandle(my_entry.fh); | ||
611 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n", | 820 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n", |
612 | dentry->d_parent->d_name.name, dentry->d_name.name, | 821 | dentry->d_parent->d_name.name, dentry->d_name.name, |
613 | res); | 822 | res); |
@@ -1029,10 +1238,63 @@ static int is_atomic_open(struct nameidata *nd) | |||
1029 | return 1; | 1238 | return 1; |
1030 | } | 1239 | } |
1031 | 1240 | ||
1241 | static struct nfs_open_context *nameidata_to_nfs_open_context(struct dentry *dentry, struct nameidata *nd) | ||
1242 | { | ||
1243 | struct path path = { | ||
1244 | .mnt = nd->path.mnt, | ||
1245 | .dentry = dentry, | ||
1246 | }; | ||
1247 | struct nfs_open_context *ctx; | ||
1248 | struct rpc_cred *cred; | ||
1249 | fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); | ||
1250 | |||
1251 | cred = rpc_lookup_cred(); | ||
1252 | if (IS_ERR(cred)) | ||
1253 | return ERR_CAST(cred); | ||
1254 | ctx = alloc_nfs_open_context(&path, cred, fmode); | ||
1255 | put_rpccred(cred); | ||
1256 | if (ctx == NULL) | ||
1257 | return ERR_PTR(-ENOMEM); | ||
1258 | return ctx; | ||
1259 | } | ||
1260 | |||
1261 | static int do_open(struct inode *inode, struct file *filp) | ||
1262 | { | ||
1263 | nfs_fscache_set_inode_cookie(inode, filp); | ||
1264 | return 0; | ||
1265 | } | ||
1266 | |||
1267 | static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx) | ||
1268 | { | ||
1269 | struct file *filp; | ||
1270 | int ret = 0; | ||
1271 | |||
1272 | /* If the open_intent is for execute, we have an extra check to make */ | ||
1273 | if (ctx->mode & FMODE_EXEC) { | ||
1274 | ret = nfs_may_open(ctx->path.dentry->d_inode, | ||
1275 | ctx->cred, | ||
1276 | nd->intent.open.flags); | ||
1277 | if (ret < 0) | ||
1278 | goto out; | ||
1279 | } | ||
1280 | filp = lookup_instantiate_filp(nd, ctx->path.dentry, do_open); | ||
1281 | if (IS_ERR(filp)) | ||
1282 | ret = PTR_ERR(filp); | ||
1283 | else | ||
1284 | nfs_file_set_open_context(filp, ctx); | ||
1285 | out: | ||
1286 | put_nfs_open_context(ctx); | ||
1287 | return ret; | ||
1288 | } | ||
1289 | |||
1032 | static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 1290 | static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
1033 | { | 1291 | { |
1292 | struct nfs_open_context *ctx; | ||
1293 | struct iattr attr; | ||
1034 | struct dentry *res = NULL; | 1294 | struct dentry *res = NULL; |
1035 | int error; | 1295 | struct inode *inode; |
1296 | int open_flags; | ||
1297 | int err; | ||
1036 | 1298 | ||
1037 | dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n", | 1299 | dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n", |
1038 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); | 1300 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
@@ -1054,13 +1316,32 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1054 | goto out; | 1316 | goto out; |
1055 | } | 1317 | } |
1056 | 1318 | ||
1319 | ctx = nameidata_to_nfs_open_context(dentry, nd); | ||
1320 | res = ERR_CAST(ctx); | ||
1321 | if (IS_ERR(ctx)) | ||
1322 | goto out; | ||
1323 | |||
1324 | open_flags = nd->intent.open.flags; | ||
1325 | if (nd->flags & LOOKUP_CREATE) { | ||
1326 | attr.ia_mode = nd->intent.open.create_mode; | ||
1327 | attr.ia_valid = ATTR_MODE; | ||
1328 | if (!IS_POSIXACL(dir)) | ||
1329 | attr.ia_mode &= ~current_umask(); | ||
1330 | } else { | ||
1331 | open_flags &= ~(O_EXCL | O_CREAT); | ||
1332 | attr.ia_valid = 0; | ||
1333 | } | ||
1334 | |||
1057 | /* Open the file on the server */ | 1335 | /* Open the file on the server */ |
1058 | res = nfs4_atomic_open(dir, dentry, nd); | 1336 | nfs_block_sillyrename(dentry->d_parent); |
1059 | if (IS_ERR(res)) { | 1337 | inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr); |
1060 | error = PTR_ERR(res); | 1338 | if (IS_ERR(inode)) { |
1061 | switch (error) { | 1339 | nfs_unblock_sillyrename(dentry->d_parent); |
1340 | put_nfs_open_context(ctx); | ||
1341 | switch (PTR_ERR(inode)) { | ||
1062 | /* Make a negative dentry */ | 1342 | /* Make a negative dentry */ |
1063 | case -ENOENT: | 1343 | case -ENOENT: |
1344 | d_add(dentry, NULL); | ||
1064 | res = NULL; | 1345 | res = NULL; |
1065 | goto out; | 1346 | goto out; |
1066 | /* This turned out not to be a regular file */ | 1347 | /* This turned out not to be a regular file */ |
@@ -1072,11 +1353,25 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1072 | goto no_open; | 1353 | goto no_open; |
1073 | /* case -EINVAL: */ | 1354 | /* case -EINVAL: */ |
1074 | default: | 1355 | default: |
1356 | res = ERR_CAST(inode); | ||
1075 | goto out; | 1357 | goto out; |
1076 | } | 1358 | } |
1077 | } else if (res != NULL) | 1359 | } |
1360 | res = d_add_unique(dentry, inode); | ||
1361 | nfs_unblock_sillyrename(dentry->d_parent); | ||
1362 | if (res != NULL) { | ||
1363 | dput(ctx->path.dentry); | ||
1364 | ctx->path.dentry = dget(res); | ||
1078 | dentry = res; | 1365 | dentry = res; |
1366 | } | ||
1367 | err = nfs_intent_set_file(nd, ctx); | ||
1368 | if (err < 0) { | ||
1369 | if (res != NULL) | ||
1370 | dput(res); | ||
1371 | return ERR_PTR(err); | ||
1372 | } | ||
1079 | out: | 1373 | out: |
1374 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1080 | return res; | 1375 | return res; |
1081 | no_open: | 1376 | no_open: |
1082 | return nfs_lookup(dir, dentry, nd); | 1377 | return nfs_lookup(dir, dentry, nd); |
@@ -1087,12 +1382,15 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1087 | struct dentry *parent = NULL; | 1382 | struct dentry *parent = NULL; |
1088 | struct inode *inode = dentry->d_inode; | 1383 | struct inode *inode = dentry->d_inode; |
1089 | struct inode *dir; | 1384 | struct inode *dir; |
1385 | struct nfs_open_context *ctx; | ||
1090 | int openflags, ret = 0; | 1386 | int openflags, ret = 0; |
1091 | 1387 | ||
1092 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) | 1388 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) |
1093 | goto no_open; | 1389 | goto no_open; |
1390 | |||
1094 | parent = dget_parent(dentry); | 1391 | parent = dget_parent(dentry); |
1095 | dir = parent->d_inode; | 1392 | dir = parent->d_inode; |
1393 | |||
1096 | /* We can't create new files in nfs_open_revalidate(), so we | 1394 | /* We can't create new files in nfs_open_revalidate(), so we |
1097 | * optimize away revalidation of negative dentries. | 1395 | * optimize away revalidation of negative dentries. |
1098 | */ | 1396 | */ |
@@ -1112,99 +1410,96 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1112 | /* We can't create new files, or truncate existing ones here */ | 1410 | /* We can't create new files, or truncate existing ones here */ |
1113 | openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); | 1411 | openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); |
1114 | 1412 | ||
1413 | ctx = nameidata_to_nfs_open_context(dentry, nd); | ||
1414 | ret = PTR_ERR(ctx); | ||
1415 | if (IS_ERR(ctx)) | ||
1416 | goto out; | ||
1115 | /* | 1417 | /* |
1116 | * Note: we're not holding inode->i_mutex and so may be racing with | 1418 | * Note: we're not holding inode->i_mutex and so may be racing with |
1117 | * operations that change the directory. We therefore save the | 1419 | * operations that change the directory. We therefore save the |
1118 | * change attribute *before* we do the RPC call. | 1420 | * change attribute *before* we do the RPC call. |
1119 | */ | 1421 | */ |
1120 | ret = nfs4_open_revalidate(dir, dentry, openflags, nd); | 1422 | inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL); |
1423 | if (IS_ERR(inode)) { | ||
1424 | ret = PTR_ERR(inode); | ||
1425 | switch (ret) { | ||
1426 | case -EPERM: | ||
1427 | case -EACCES: | ||
1428 | case -EDQUOT: | ||
1429 | case -ENOSPC: | ||
1430 | case -EROFS: | ||
1431 | goto out_put_ctx; | ||
1432 | default: | ||
1433 | goto out_drop; | ||
1434 | } | ||
1435 | } | ||
1436 | iput(inode); | ||
1437 | if (inode != dentry->d_inode) | ||
1438 | goto out_drop; | ||
1439 | |||
1440 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1441 | ret = nfs_intent_set_file(nd, ctx); | ||
1442 | if (ret >= 0) | ||
1443 | ret = 1; | ||
1121 | out: | 1444 | out: |
1122 | dput(parent); | 1445 | dput(parent); |
1123 | if (!ret) | ||
1124 | d_drop(dentry); | ||
1125 | return ret; | 1446 | return ret; |
1447 | out_drop: | ||
1448 | d_drop(dentry); | ||
1449 | ret = 0; | ||
1450 | out_put_ctx: | ||
1451 | put_nfs_open_context(ctx); | ||
1452 | goto out; | ||
1453 | |||
1126 | no_open_dput: | 1454 | no_open_dput: |
1127 | dput(parent); | 1455 | dput(parent); |
1128 | no_open: | 1456 | no_open: |
1129 | return nfs_lookup_revalidate(dentry, nd); | 1457 | return nfs_lookup_revalidate(dentry, nd); |
1130 | } | 1458 | } |
1131 | #endif /* CONFIG_NFSV4 */ | ||
1132 | 1459 | ||
1133 | static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) | 1460 | static int nfs_open_create(struct inode *dir, struct dentry *dentry, int mode, |
1461 | struct nameidata *nd) | ||
1134 | { | 1462 | { |
1135 | struct dentry *parent = desc->file->f_path.dentry; | 1463 | struct nfs_open_context *ctx = NULL; |
1136 | struct inode *dir = parent->d_inode; | 1464 | struct iattr attr; |
1137 | struct nfs_entry *entry = desc->entry; | 1465 | int error; |
1138 | struct dentry *dentry, *alias; | 1466 | int open_flags = 0; |
1139 | struct qstr name = { | ||
1140 | .name = entry->name, | ||
1141 | .len = entry->len, | ||
1142 | }; | ||
1143 | struct inode *inode; | ||
1144 | unsigned long verf = nfs_save_change_attribute(dir); | ||
1145 | 1467 | ||
1146 | switch (name.len) { | 1468 | dfprintk(VFS, "NFS: create(%s/%ld), %s\n", |
1147 | case 2: | 1469 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1148 | if (name.name[0] == '.' && name.name[1] == '.') | ||
1149 | return dget_parent(parent); | ||
1150 | break; | ||
1151 | case 1: | ||
1152 | if (name.name[0] == '.') | ||
1153 | return dget(parent); | ||
1154 | } | ||
1155 | 1470 | ||
1156 | spin_lock(&dir->i_lock); | 1471 | attr.ia_mode = mode; |
1157 | if (NFS_I(dir)->cache_validity & NFS_INO_INVALID_DATA) { | 1472 | attr.ia_valid = ATTR_MODE; |
1158 | spin_unlock(&dir->i_lock); | ||
1159 | return NULL; | ||
1160 | } | ||
1161 | spin_unlock(&dir->i_lock); | ||
1162 | 1473 | ||
1163 | name.hash = full_name_hash(name.name, name.len); | 1474 | if ((nd->flags & LOOKUP_CREATE) != 0) { |
1164 | dentry = d_lookup(parent, &name); | 1475 | open_flags = nd->intent.open.flags; |
1165 | if (dentry != NULL) { | ||
1166 | /* Is this a positive dentry that matches the readdir info? */ | ||
1167 | if (dentry->d_inode != NULL && | ||
1168 | (NFS_FILEID(dentry->d_inode) == entry->ino || | ||
1169 | d_mountpoint(dentry))) { | ||
1170 | if (!desc->plus || entry->fh->size == 0) | ||
1171 | return dentry; | ||
1172 | if (nfs_compare_fh(NFS_FH(dentry->d_inode), | ||
1173 | entry->fh) == 0) | ||
1174 | goto out_renew; | ||
1175 | } | ||
1176 | /* No, so d_drop to allow one to be created */ | ||
1177 | d_drop(dentry); | ||
1178 | dput(dentry); | ||
1179 | } | ||
1180 | if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR)) | ||
1181 | return NULL; | ||
1182 | if (name.len > NFS_SERVER(dir)->namelen) | ||
1183 | return NULL; | ||
1184 | /* Note: caller is already holding the dir->i_mutex! */ | ||
1185 | dentry = d_alloc(parent, &name); | ||
1186 | if (dentry == NULL) | ||
1187 | return NULL; | ||
1188 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | ||
1189 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); | ||
1190 | if (IS_ERR(inode)) { | ||
1191 | dput(dentry); | ||
1192 | return NULL; | ||
1193 | } | ||
1194 | 1476 | ||
1195 | alias = d_materialise_unique(dentry, inode); | 1477 | ctx = nameidata_to_nfs_open_context(dentry, nd); |
1196 | if (alias != NULL) { | 1478 | error = PTR_ERR(ctx); |
1197 | dput(dentry); | 1479 | if (IS_ERR(ctx)) |
1198 | if (IS_ERR(alias)) | 1480 | goto out_err_drop; |
1199 | return NULL; | ||
1200 | dentry = alias; | ||
1201 | } | 1481 | } |
1202 | 1482 | ||
1203 | out_renew: | 1483 | error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx); |
1204 | nfs_set_verifier(dentry, verf); | 1484 | if (error != 0) |
1205 | return dentry; | 1485 | goto out_put_ctx; |
1486 | if (ctx != NULL) { | ||
1487 | error = nfs_intent_set_file(nd, ctx); | ||
1488 | if (error < 0) | ||
1489 | goto out_err; | ||
1490 | } | ||
1491 | return 0; | ||
1492 | out_put_ctx: | ||
1493 | if (ctx != NULL) | ||
1494 | put_nfs_open_context(ctx); | ||
1495 | out_err_drop: | ||
1496 | d_drop(dentry); | ||
1497 | out_err: | ||
1498 | return error; | ||
1206 | } | 1499 | } |
1207 | 1500 | ||
1501 | #endif /* CONFIG_NFSV4 */ | ||
1502 | |||
1208 | /* | 1503 | /* |
1209 | * Code common to create, mkdir, and mknod. | 1504 | * Code common to create, mkdir, and mknod. |
1210 | */ | 1505 | */ |
@@ -1258,7 +1553,6 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
1258 | { | 1553 | { |
1259 | struct iattr attr; | 1554 | struct iattr attr; |
1260 | int error; | 1555 | int error; |
1261 | int open_flags = 0; | ||
1262 | 1556 | ||
1263 | dfprintk(VFS, "NFS: create(%s/%ld), %s\n", | 1557 | dfprintk(VFS, "NFS: create(%s/%ld), %s\n", |
1264 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); | 1558 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
@@ -1266,10 +1560,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
1266 | attr.ia_mode = mode; | 1560 | attr.ia_mode = mode; |
1267 | attr.ia_valid = ATTR_MODE; | 1561 | attr.ia_valid = ATTR_MODE; |
1268 | 1562 | ||
1269 | if ((nd->flags & LOOKUP_CREATE) != 0) | 1563 | error = NFS_PROTO(dir)->create(dir, dentry, &attr, 0, NULL); |
1270 | open_flags = nd->intent.open.flags; | ||
1271 | |||
1272 | error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd); | ||
1273 | if (error != 0) | 1564 | if (error != 0) |
1274 | goto out_err; | 1565 | goto out_err; |
1275 | return 0; | 1566 | return 0; |
@@ -1351,76 +1642,6 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1351 | return error; | 1642 | return error; |
1352 | } | 1643 | } |
1353 | 1644 | ||
1354 | static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) | ||
1355 | { | ||
1356 | static unsigned int sillycounter; | ||
1357 | const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2; | ||
1358 | const int countersize = sizeof(sillycounter)*2; | ||
1359 | const int slen = sizeof(".nfs")+fileidsize+countersize-1; | ||
1360 | char silly[slen+1]; | ||
1361 | struct qstr qsilly; | ||
1362 | struct dentry *sdentry; | ||
1363 | int error = -EIO; | ||
1364 | |||
1365 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", | ||
1366 | dentry->d_parent->d_name.name, dentry->d_name.name, | ||
1367 | atomic_read(&dentry->d_count)); | ||
1368 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); | ||
1369 | |||
1370 | /* | ||
1371 | * We don't allow a dentry to be silly-renamed twice. | ||
1372 | */ | ||
1373 | error = -EBUSY; | ||
1374 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) | ||
1375 | goto out; | ||
1376 | |||
1377 | sprintf(silly, ".nfs%*.*Lx", | ||
1378 | fileidsize, fileidsize, | ||
1379 | (unsigned long long)NFS_FILEID(dentry->d_inode)); | ||
1380 | |||
1381 | /* Return delegation in anticipation of the rename */ | ||
1382 | nfs_inode_return_delegation(dentry->d_inode); | ||
1383 | |||
1384 | sdentry = NULL; | ||
1385 | do { | ||
1386 | char *suffix = silly + slen - countersize; | ||
1387 | |||
1388 | dput(sdentry); | ||
1389 | sillycounter++; | ||
1390 | sprintf(suffix, "%*.*x", countersize, countersize, sillycounter); | ||
1391 | |||
1392 | dfprintk(VFS, "NFS: trying to rename %s to %s\n", | ||
1393 | dentry->d_name.name, silly); | ||
1394 | |||
1395 | sdentry = lookup_one_len(silly, dentry->d_parent, slen); | ||
1396 | /* | ||
1397 | * N.B. Better to return EBUSY here ... it could be | ||
1398 | * dangerous to delete the file while it's in use. | ||
1399 | */ | ||
1400 | if (IS_ERR(sdentry)) | ||
1401 | goto out; | ||
1402 | } while(sdentry->d_inode != NULL); /* need negative lookup */ | ||
1403 | |||
1404 | qsilly.name = silly; | ||
1405 | qsilly.len = strlen(silly); | ||
1406 | if (dentry->d_inode) { | ||
1407 | error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, | ||
1408 | dir, &qsilly); | ||
1409 | nfs_mark_for_revalidate(dentry->d_inode); | ||
1410 | } else | ||
1411 | error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, | ||
1412 | dir, &qsilly); | ||
1413 | if (!error) { | ||
1414 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1415 | d_move(dentry, sdentry); | ||
1416 | error = nfs_async_unlink(dir, dentry); | ||
1417 | /* If we return 0 we don't unlink */ | ||
1418 | } | ||
1419 | dput(sdentry); | ||
1420 | out: | ||
1421 | return error; | ||
1422 | } | ||
1423 | |||
1424 | /* | 1645 | /* |
1425 | * Remove a file after making sure there are no pending writes, | 1646 | * Remove a file after making sure there are no pending writes, |
1426 | * and after checking that the file has only one user. | 1647 | * and after checking that the file has only one user. |
@@ -1711,14 +1932,14 @@ static void nfs_access_free_list(struct list_head *head) | |||
1711 | int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) | 1932 | int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) |
1712 | { | 1933 | { |
1713 | LIST_HEAD(head); | 1934 | LIST_HEAD(head); |
1714 | struct nfs_inode *nfsi; | 1935 | struct nfs_inode *nfsi, *next; |
1715 | struct nfs_access_entry *cache; | 1936 | struct nfs_access_entry *cache; |
1716 | 1937 | ||
1717 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) | 1938 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) |
1718 | return (nr_to_scan == 0) ? 0 : -1; | 1939 | return (nr_to_scan == 0) ? 0 : -1; |
1719 | 1940 | ||
1720 | spin_lock(&nfs_access_lru_lock); | 1941 | spin_lock(&nfs_access_lru_lock); |
1721 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | 1942 | list_for_each_entry_safe(nfsi, next, &nfs_access_lru_list, access_cache_inode_lru) { |
1722 | struct inode *inode; | 1943 | struct inode *inode; |
1723 | 1944 | ||
1724 | if (nr_to_scan-- == 0) | 1945 | if (nr_to_scan-- == 0) |