diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 33b0ce7a97be..fd30f185ec01 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -370,6 +370,71 @@ int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, __be32 * | |||
370 | return 0; | 370 | return 0; |
371 | } | 371 | } |
372 | 372 | ||
373 | static | ||
374 | int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) | ||
375 | { | ||
376 | struct nfs_inode *node; | ||
377 | if (dentry->d_inode == NULL) | ||
378 | goto different; | ||
379 | node = NFS_I(dentry->d_inode); | ||
380 | if (node->fh.size != entry->fh->size) | ||
381 | goto different; | ||
382 | if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0) | ||
383 | goto different; | ||
384 | return 1; | ||
385 | different: | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static | ||
390 | void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | ||
391 | { | ||
392 | struct qstr filename; | ||
393 | struct dentry *dentry = NULL; | ||
394 | struct dentry *alias = NULL; | ||
395 | struct inode *dir = parent->d_inode; | ||
396 | struct inode *inode; | ||
397 | |||
398 | nfs_readdir_make_qstr(&filename, entry->name, entry->len); | ||
399 | if (filename.len == 1 && filename.name[0] == '.') | ||
400 | dentry = dget(parent); | ||
401 | else if (filename.len == 2 && filename.name[0] == '.' | ||
402 | && filename.name[1] == '.') | ||
403 | dentry = dget_parent(parent); | ||
404 | else | ||
405 | dentry = d_lookup(parent, &filename); | ||
406 | |||
407 | if (dentry != NULL) { | ||
408 | if (nfs_same_file(dentry, entry)) { | ||
409 | nfs_refresh_inode(dentry->d_inode, entry->fattr); | ||
410 | goto out; | ||
411 | } else { | ||
412 | d_drop(dentry); | ||
413 | dput(dentry); | ||
414 | } | ||
415 | } | ||
416 | |||
417 | dentry = d_alloc(parent, &filename); | ||
418 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | ||
419 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); | ||
420 | if (IS_ERR(inode)) | ||
421 | goto out; | ||
422 | |||
423 | alias = d_materialise_unique(dentry, inode); | ||
424 | if (IS_ERR(alias)) | ||
425 | goto out; | ||
426 | else if (alias) { | ||
427 | nfs_set_verifier(alias, nfs_save_change_attribute(dir)); | ||
428 | dput(alias); | ||
429 | } else | ||
430 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
431 | |||
432 | out: | ||
433 | dput(dentry); | ||
434 | kfree(filename.name); | ||
435 | return; | ||
436 | } | ||
437 | |||
373 | /* Perform conversion from xdr to cache array */ | 438 | /* Perform conversion from xdr to cache array */ |
374 | static | 439 | static |
375 | void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, | 440 | void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, |
@@ -379,6 +444,8 @@ void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *e | |||
379 | while (xdr_decode(desc, entry, &ptr) == 0) { | 444 | while (xdr_decode(desc, entry, &ptr) == 0) { |
380 | if (nfs_readdir_add_to_array(entry, page) == -1) | 445 | if (nfs_readdir_add_to_array(entry, page) == -1) |
381 | break; | 446 | break; |
447 | if (desc->plus == 1) | ||
448 | nfs_prime_dcache(desc->file->f_path.dentry, entry); | ||
382 | } | 449 | } |
383 | kunmap(xdr_page); | 450 | kunmap(xdr_page); |
384 | } | 451 | } |