1 /* 2 * (C) 2001 Clemson University and The University of Chicago 3 * 4 * See COPYING in top-level directory. 5 */ 6 7 /* 8 * Implementation of dentry (directory cache) functions. 9 */ 10 11 #include "protocol.h" 12 #include "orangefs-kernel.h" 13 14 /* Returns 1 if dentry can still be trusted, else 0. */ 15 static int orangefs_revalidate_lookup(struct dentry *dentry) 16 { 17 struct dentry *parent_dentry = dget_parent(dentry); 18 struct inode *parent_inode = parent_dentry->d_inode; 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 goto out_put_parent; 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 strncpy(new_op->upcall.req.lookup.d_name, 34 dentry->d_name.name, 35 ORANGEFS_NAME_MAX); 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 ret = 1; 77 out_release_op: 78 op_release(new_op); 79 out_put_parent: 80 dput(parent_dentry); 81 return ret; 82 out_drop: 83 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n", 84 __FILE__, __func__, __LINE__); 85 goto out_release_op; 86 } 87 88 /* 89 * Verify that dentry is valid. 90 * 91 * Should return 1 if dentry can still be trusted, else 0. 92 */ 93 static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags) 94 { 95 int ret; 96 97 if (flags & LOOKUP_RCU) 98 return -ECHILD; 99 100 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n", 101 __func__, dentry); 102 103 /* skip root handle lookups. */ 104 if (dentry->d_inode && is_root_handle(dentry->d_inode)) 105 return 1; 106 107 /* 108 * If this passes, the positive dentry still exists or the negative 109 * dentry still does not exist. 110 */ 111 if (!orangefs_revalidate_lookup(dentry)) 112 return 0; 113 114 /* We do not need to continue with negative dentries. */ 115 if (!dentry->d_inode) 116 goto out; 117 118 /* Now we must perform a getattr to validate the inode contents. */ 119 120 ret = orangefs_inode_check_changed(dentry->d_inode); 121 if (ret < 0) { 122 gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n", 123 __FILE__, __func__, __LINE__); 124 return 0; 125 } 126 if (ret == 0) 127 return 0; 128 129 out: 130 gossip_debug(GOSSIP_DCACHE_DEBUG, 131 "%s: negative dentry or positive dentry and inode valid.\n", 132 __func__); 133 return 1; 134 } 135 136 const struct dentry_operations orangefs_dentry_operations = { 137 .d_revalidate = orangefs_d_revalidate, 138 }; 139