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