GNU Linux-libre 4.19.211-gnu1
[releases.git] / fs / orangefs / dcache.c
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. */
16 static 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;
79 out_release_op:
80         op_release(new_op);
81 out_put_parent:
82         dput(parent_dentry);
83         return ret;
84 out_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  */
95 static 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
139 const struct dentry_operations orangefs_dentry_operations = {
140         .d_revalidate = orangefs_d_revalidate,
141 };