162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (C) 2001 Clemson University and The University of Chicago 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * See COPYING in top-level directory. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * Implementation of dentry (directory cache) functions. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "protocol.h" 1362306a36Sopenharmony_ci#include "orangefs-kernel.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* Returns 1 if dentry can still be trusted, else 0. */ 1662306a36Sopenharmony_cistatic int orangefs_revalidate_lookup(struct dentry *dentry) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci struct dentry *parent_dentry = dget_parent(dentry); 1962306a36Sopenharmony_ci struct inode *parent_inode = parent_dentry->d_inode; 2062306a36Sopenharmony_ci struct orangefs_inode_s *parent = ORANGEFS_I(parent_inode); 2162306a36Sopenharmony_ci struct inode *inode = dentry->d_inode; 2262306a36Sopenharmony_ci struct orangefs_kernel_op_s *new_op; 2362306a36Sopenharmony_ci int ret = 0; 2462306a36Sopenharmony_ci int err = 0; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: attempting lookup.\n", __func__); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP); 2962306a36Sopenharmony_ci if (!new_op) { 3062306a36Sopenharmony_ci ret = -ENOMEM; 3162306a36Sopenharmony_ci goto out_put_parent; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW; 3562306a36Sopenharmony_ci new_op->upcall.req.lookup.parent_refn = parent->refn; 3662306a36Sopenharmony_ci strncpy(new_op->upcall.req.lookup.d_name, 3762306a36Sopenharmony_ci dentry->d_name.name, 3862306a36Sopenharmony_ci ORANGEFS_NAME_MAX - 1); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, 4162306a36Sopenharmony_ci "%s:%s:%d interrupt flag [%d]\n", 4262306a36Sopenharmony_ci __FILE__, 4362306a36Sopenharmony_ci __func__, 4462306a36Sopenharmony_ci __LINE__, 4562306a36Sopenharmony_ci get_interruptible_flag(parent_inode)); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci err = service_operation(new_op, "orangefs_lookup", 4862306a36Sopenharmony_ci get_interruptible_flag(parent_inode)); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* Positive dentry: reject if error or not the same inode. */ 5162306a36Sopenharmony_ci if (inode) { 5262306a36Sopenharmony_ci if (err) { 5362306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, 5462306a36Sopenharmony_ci "%s:%s:%d lookup failure.\n", 5562306a36Sopenharmony_ci __FILE__, __func__, __LINE__); 5662306a36Sopenharmony_ci goto out_drop; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci if (!match_handle(new_op->downcall.resp.lookup.refn.khandle, 5962306a36Sopenharmony_ci inode)) { 6062306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, 6162306a36Sopenharmony_ci "%s:%s:%d no match.\n", 6262306a36Sopenharmony_ci __FILE__, __func__, __LINE__); 6362306a36Sopenharmony_ci goto out_drop; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* Negative dentry: reject if success or error other than ENOENT. */ 6762306a36Sopenharmony_ci } else { 6862306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: negative dentry.\n", 6962306a36Sopenharmony_ci __func__); 7062306a36Sopenharmony_ci if (!err || err != -ENOENT) { 7162306a36Sopenharmony_ci if (new_op->downcall.status != 0) 7262306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, 7362306a36Sopenharmony_ci "%s:%s:%d lookup failure.\n", 7462306a36Sopenharmony_ci __FILE__, __func__, __LINE__); 7562306a36Sopenharmony_ci goto out_drop; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci orangefs_set_timeout(dentry); 8062306a36Sopenharmony_ci ret = 1; 8162306a36Sopenharmony_ciout_release_op: 8262306a36Sopenharmony_ci op_release(new_op); 8362306a36Sopenharmony_ciout_put_parent: 8462306a36Sopenharmony_ci dput(parent_dentry); 8562306a36Sopenharmony_ci return ret; 8662306a36Sopenharmony_ciout_drop: 8762306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n", 8862306a36Sopenharmony_ci __FILE__, __func__, __LINE__); 8962306a36Sopenharmony_ci goto out_release_op; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * Verify that dentry is valid. 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * Should return 1 if dentry can still be trusted, else 0. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_cistatic int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci int ret; 10062306a36Sopenharmony_ci unsigned long time = (unsigned long) dentry->d_fsdata; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (time_before(jiffies, time)) 10362306a36Sopenharmony_ci return 1; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (flags & LOOKUP_RCU) 10662306a36Sopenharmony_ci return -ECHILD; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n", 10962306a36Sopenharmony_ci __func__, dentry); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* skip root handle lookups. */ 11262306a36Sopenharmony_ci if (dentry->d_inode && is_root_handle(dentry->d_inode)) 11362306a36Sopenharmony_ci return 1; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * If this passes, the positive dentry still exists or the negative 11762306a36Sopenharmony_ci * dentry still does not exist. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci if (!orangefs_revalidate_lookup(dentry)) 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* We do not need to continue with negative dentries. */ 12362306a36Sopenharmony_ci if (!dentry->d_inode) { 12462306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, 12562306a36Sopenharmony_ci "%s: negative dentry or positive dentry and inode valid.\n", 12662306a36Sopenharmony_ci __func__); 12762306a36Sopenharmony_ci return 1; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Now we must perform a getattr to validate the inode contents. */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ret = orangefs_inode_check_changed(dentry->d_inode); 13362306a36Sopenharmony_ci if (ret < 0) { 13462306a36Sopenharmony_ci gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n", 13562306a36Sopenharmony_ci __FILE__, __func__, __LINE__); 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci return !ret; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciconst struct dentry_operations orangefs_dentry_operations = { 14262306a36Sopenharmony_ci .d_revalidate = orangefs_d_revalidate, 14362306a36Sopenharmony_ci}; 144