dcache.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * (C) 2001 Clemson University and The University of Chicago
  4. *
  5. * See COPYING in top-level directory.
  6. */
  7. /*
  8. * Implementation of dentry (directory cache) functions.
  9. */
  10. #include "protocol.h"
  11. #include "orangefs-kernel.h"
  12. /* Returns 1 if dentry can still be trusted, else 0. */
  13. static int orangefs_revalidate_lookup(struct dentry *dentry)
  14. {
  15. struct dentry *parent_dentry = dget_parent(dentry);
  16. struct inode *parent_inode = parent_dentry->d_inode;
  17. struct orangefs_inode_s *parent = ORANGEFS_I(parent_inode);
  18. struct inode *inode = dentry->d_inode;
  19. struct orangefs_kernel_op_s *new_op;
  20. int ret = 0;
  21. int err = 0;
  22. gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: attempting lookup.\n", __func__);
  23. new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
  24. if (!new_op) {
  25. ret = -ENOMEM;
  26. goto out_put_parent;
  27. }
  28. new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
  29. new_op->upcall.req.lookup.parent_refn = parent->refn;
  30. strncpy(new_op->upcall.req.lookup.d_name,
  31. dentry->d_name.name,
  32. ORANGEFS_NAME_MAX - 1);
  33. gossip_debug(GOSSIP_DCACHE_DEBUG,
  34. "%s:%s:%d interrupt flag [%d]\n",
  35. __FILE__,
  36. __func__,
  37. __LINE__,
  38. get_interruptible_flag(parent_inode));
  39. err = service_operation(new_op, "orangefs_lookup",
  40. get_interruptible_flag(parent_inode));
  41. /* Positive dentry: reject if error or not the same inode. */
  42. if (inode) {
  43. if (err) {
  44. gossip_debug(GOSSIP_DCACHE_DEBUG,
  45. "%s:%s:%d lookup failure.\n",
  46. __FILE__, __func__, __LINE__);
  47. goto out_drop;
  48. }
  49. if (!match_handle(new_op->downcall.resp.lookup.refn.khandle,
  50. inode)) {
  51. gossip_debug(GOSSIP_DCACHE_DEBUG,
  52. "%s:%s:%d no match.\n",
  53. __FILE__, __func__, __LINE__);
  54. goto out_drop;
  55. }
  56. /* Negative dentry: reject if success or error other than ENOENT. */
  57. } else {
  58. gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: negative dentry.\n",
  59. __func__);
  60. if (!err || err != -ENOENT) {
  61. if (new_op->downcall.status != 0)
  62. gossip_debug(GOSSIP_DCACHE_DEBUG,
  63. "%s:%s:%d lookup failure.\n",
  64. __FILE__, __func__, __LINE__);
  65. goto out_drop;
  66. }
  67. }
  68. orangefs_set_timeout(dentry);
  69. ret = 1;
  70. out_release_op:
  71. op_release(new_op);
  72. out_put_parent:
  73. dput(parent_dentry);
  74. return ret;
  75. out_drop:
  76. gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n",
  77. __FILE__, __func__, __LINE__);
  78. goto out_release_op;
  79. }
  80. /*
  81. * Verify that dentry is valid.
  82. *
  83. * Should return 1 if dentry can still be trusted, else 0.
  84. */
  85. static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
  86. {
  87. int ret;
  88. unsigned long time = (unsigned long) dentry->d_fsdata;
  89. if (time_before(jiffies, time))
  90. return 1;
  91. if (flags & LOOKUP_RCU)
  92. return -ECHILD;
  93. gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n",
  94. __func__, dentry);
  95. /* skip root handle lookups. */
  96. if (dentry->d_inode && is_root_handle(dentry->d_inode))
  97. return 1;
  98. /*
  99. * If this passes, the positive dentry still exists or the negative
  100. * dentry still does not exist.
  101. */
  102. if (!orangefs_revalidate_lookup(dentry))
  103. return 0;
  104. /* We do not need to continue with negative dentries. */
  105. if (!dentry->d_inode) {
  106. gossip_debug(GOSSIP_DCACHE_DEBUG,
  107. "%s: negative dentry or positive dentry and inode valid.\n",
  108. __func__);
  109. return 1;
  110. }
  111. /* Now we must perform a getattr to validate the inode contents. */
  112. ret = orangefs_inode_check_changed(dentry->d_inode);
  113. if (ret < 0) {
  114. gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n",
  115. __FILE__, __func__, __LINE__);
  116. return 0;
  117. }
  118. return !ret;
  119. }
  120. const struct dentry_operations orangefs_dentry_operations = {
  121. .d_revalidate = orangefs_d_revalidate,
  122. };