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