dcache.c 3.6 KB

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