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