afs: Move the vnode/volume validity checking code into its own file
[sfrench/cifs-2.6.git] / fs / afs / validation.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* vnode and volume validity verification.
3  *
4  * Copyright (C) 2023 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  */
7
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/sched.h>
11 #include "internal.h"
12
13 /*
14  * mark the data attached to an inode as obsolete due to a write on the server
15  * - might also want to ditch all the outstanding writes and dirty pages
16  */
17 static void afs_zap_data(struct afs_vnode *vnode)
18 {
19         _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
20
21         afs_invalidate_cache(vnode, 0);
22
23         /* nuke all the non-dirty pages that aren't locked, mapped or being
24          * written back in a regular file and completely discard the pages in a
25          * directory or symlink */
26         if (S_ISREG(vnode->netfs.inode.i_mode))
27                 invalidate_remote_inode(&vnode->netfs.inode);
28         else
29                 invalidate_inode_pages2(vnode->netfs.inode.i_mapping);
30 }
31
32 /*
33  * Check to see if we have a server currently serving this volume and that it
34  * hasn't been reinitialised or dropped from the list.
35  */
36 static bool afs_check_server_good(struct afs_vnode *vnode)
37 {
38         struct afs_server_list *slist;
39         struct afs_server *server;
40         bool good;
41         int i;
42
43         if (vnode->cb_fs_s_break == atomic_read(&vnode->volume->cell->fs_s_break))
44                 return true;
45
46         rcu_read_lock();
47
48         slist = rcu_dereference(vnode->volume->servers);
49         for (i = 0; i < slist->nr_servers; i++) {
50                 server = slist->servers[i].server;
51                 if (server == vnode->cb_server) {
52                         good = (vnode->cb_s_break == server->cb_s_break);
53                         rcu_read_unlock();
54                         return good;
55                 }
56         }
57
58         rcu_read_unlock();
59         return false;
60 }
61
62 /*
63  * Check the validity of a vnode/inode.
64  */
65 bool afs_check_validity(struct afs_vnode *vnode)
66 {
67         enum afs_cb_break_reason need_clear = afs_cb_break_no_break;
68         time64_t now = ktime_get_real_seconds();
69         unsigned int cb_break;
70         int seq;
71
72         do {
73                 seq = read_seqbegin(&vnode->cb_lock);
74                 cb_break = vnode->cb_break;
75
76                 if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
77                         if (vnode->cb_v_break != vnode->volume->cb_v_break)
78                                 need_clear = afs_cb_break_for_v_break;
79                         else if (!afs_check_server_good(vnode))
80                                 need_clear = afs_cb_break_for_s_reinit;
81                         else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
82                                 need_clear = afs_cb_break_for_zap;
83                         else if (vnode->cb_expires_at - 10 <= now)
84                                 need_clear = afs_cb_break_for_lapsed;
85                 } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
86                         ;
87                 } else {
88                         need_clear = afs_cb_break_no_promise;
89                 }
90
91         } while (read_seqretry(&vnode->cb_lock, seq));
92
93         if (need_clear == afs_cb_break_no_break)
94                 return true;
95
96         write_seqlock(&vnode->cb_lock);
97         if (need_clear == afs_cb_break_no_promise)
98                 vnode->cb_v_break = vnode->volume->cb_v_break;
99         else if (cb_break == vnode->cb_break)
100                 __afs_break_callback(vnode, need_clear);
101         else
102                 trace_afs_cb_miss(&vnode->fid, need_clear);
103         write_sequnlock(&vnode->cb_lock);
104         return false;
105 }
106
107 /*
108  * Returns true if the pagecache is still valid.  Does not sleep.
109  */
110 bool afs_pagecache_valid(struct afs_vnode *vnode)
111 {
112         if (unlikely(test_bit(AFS_VNODE_DELETED, &vnode->flags))) {
113                 if (vnode->netfs.inode.i_nlink)
114                         clear_nlink(&vnode->netfs.inode);
115                 return true;
116         }
117
118         if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags) &&
119             afs_check_validity(vnode))
120                 return true;
121
122         return false;
123 }
124
125 /*
126  * validate a vnode/inode
127  * - there are several things we need to check
128  *   - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
129  *     symlink)
130  *   - parent dir metadata changed (security changes)
131  *   - dentry data changed (write, truncate)
132  *   - dentry metadata changed (security changes)
133  */
134 int afs_validate(struct afs_vnode *vnode, struct key *key)
135 {
136         int ret;
137
138         _enter("{v={%llx:%llu} fl=%lx},%x",
139                vnode->fid.vid, vnode->fid.vnode, vnode->flags,
140                key_serial(key));
141
142         if (afs_pagecache_valid(vnode))
143                 goto valid;
144
145         down_write(&vnode->validate_lock);
146
147         /* if the promise has expired, we need to check the server again to get
148          * a new promise - note that if the (parent) directory's metadata was
149          * changed then the security may be different and we may no longer have
150          * access */
151         if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
152                 _debug("not promised");
153                 ret = afs_fetch_status(vnode, key, false, NULL);
154                 if (ret < 0) {
155                         if (ret == -ENOENT) {
156                                 set_bit(AFS_VNODE_DELETED, &vnode->flags);
157                                 ret = -ESTALE;
158                         }
159                         goto error_unlock;
160                 }
161                 _debug("new promise [fl=%lx]", vnode->flags);
162         }
163
164         if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
165                 _debug("file already deleted");
166                 ret = -ESTALE;
167                 goto error_unlock;
168         }
169
170         /* if the vnode's data version number changed then its contents are
171          * different */
172         if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
173                 afs_zap_data(vnode);
174         up_write(&vnode->validate_lock);
175 valid:
176         _leave(" = 0");
177         return 0;
178
179 error_unlock:
180         up_write(&vnode->validate_lock);
181         _leave(" = %d", ret);
182         return ret;
183 }