linux/fs/orangefs/dcache.c
<<
>>
Prefs
   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. */
  15static 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        orangefs_set_timeout(dentry);
  77        ret = 1;
  78out_release_op:
  79        op_release(new_op);
  80out_put_parent:
  81        dput(parent_dentry);
  82        return ret;
  83out_drop:
  84        gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n",
  85            __FILE__, __func__, __LINE__);
  86        goto out_release_op;
  87}
  88
  89/*
  90 * Verify that dentry is valid.
  91 *
  92 * Should return 1 if dentry can still be trusted, else 0.
  93 */
  94static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
  95{
  96        int ret;
  97        unsigned long time = (unsigned long) dentry->d_fsdata;
  98
  99        if (time_before(jiffies, time))
 100                return 1;
 101
 102        if (flags & LOOKUP_RCU)
 103                return -ECHILD;
 104
 105        gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n",
 106                     __func__, dentry);
 107
 108        /* skip root handle lookups. */
 109        if (dentry->d_inode && is_root_handle(dentry->d_inode))
 110                return 1;
 111
 112        /*
 113         * If this passes, the positive dentry still exists or the negative
 114         * dentry still does not exist.
 115         */
 116        if (!orangefs_revalidate_lookup(dentry))
 117                return 0;
 118
 119        /* We do not need to continue with negative dentries. */
 120        if (!dentry->d_inode)
 121                goto out;
 122
 123        /* Now we must perform a getattr to validate the inode contents. */
 124
 125        ret = orangefs_inode_check_changed(dentry->d_inode);
 126        if (ret < 0) {
 127                gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n",
 128                    __FILE__, __func__, __LINE__);
 129                return 0;
 130        }
 131        if (ret == 0)
 132                return 0;
 133
 134out:
 135        gossip_debug(GOSSIP_DCACHE_DEBUG,
 136            "%s: negative dentry or positive dentry and inode valid.\n",
 137            __func__);
 138        return 1;
 139}
 140
 141const struct dentry_operations orangefs_dentry_operations = {
 142        .d_revalidate = orangefs_d_revalidate,
 143};
 144