aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r--fs/nfs/dir.c67
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
373static
374int 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;
385different:
386 return 0;
387}
388
389static
390void 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
432out:
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 */
374static 439static
375void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, 440void 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}