xref: /openbmc/linux/fs/afs/inode.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * This software may be freely redistributed under the terms of the
51da177e4SLinus Torvalds  * GNU General Public License.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
81da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
91da177e4SLinus Torvalds  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
101da177e4SLinus Torvalds  *
1144d1b980SDavid Woodhouse  * Authors: David Woodhouse <dwmw2@infradead.org>
121da177e4SLinus Torvalds  *          David Howells <dhowells@redhat.com>
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds #include <linux/kernel.h>
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds #include <linux/init.h>
191da177e4SLinus Torvalds #include <linux/fs.h>
201da177e4SLinus Torvalds #include <linux/pagemap.h>
21e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
22bec5eb61Swanglei #include <linux/mount.h>
23bec5eb61Swanglei #include <linux/namei.h>
24a01179e6SJeff Layton #include <linux/iversion.h>
251da177e4SLinus Torvalds #include "internal.h"
26a38a7558SDavid Howells #include "afs_fs.h"
271da177e4SLinus Torvalds 
28d3e3b7eaSDavid Howells static const struct inode_operations afs_symlink_inode_operations = {
29d3e3b7eaSDavid Howells 	.get_link	= page_get_link,
30d3e3b7eaSDavid Howells };
31d3e3b7eaSDavid Howells 
dump_vnode(struct afs_vnode * vnode,struct afs_vnode * parent_vnode)32b134d687SDavid Howells static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *parent_vnode)
33b134d687SDavid Howells {
34b134d687SDavid Howells 	static unsigned long once_only;
35b134d687SDavid Howells 
36a4e530aeSKefeng Wang 	pr_warn("kAFS: AFS vnode with undefined type %u\n", vnode->status.type);
37b134d687SDavid Howells 	pr_warn("kAFS: A=%d m=%o s=%llx v=%llx\n",
38b134d687SDavid Howells 		vnode->status.abort_code,
39b134d687SDavid Howells 		vnode->status.mode,
40b134d687SDavid Howells 		vnode->status.size,
41b134d687SDavid Howells 		vnode->status.data_version);
42b134d687SDavid Howells 	pr_warn("kAFS: vnode %llx:%llx:%x\n",
43b134d687SDavid Howells 		vnode->fid.vid,
44b134d687SDavid Howells 		vnode->fid.vnode,
45b134d687SDavid Howells 		vnode->fid.unique);
46b134d687SDavid Howells 	if (parent_vnode)
47b134d687SDavid Howells 		pr_warn("kAFS: dir %llx:%llx:%x\n",
48b134d687SDavid Howells 			parent_vnode->fid.vid,
49b134d687SDavid Howells 			parent_vnode->fid.vnode,
50b134d687SDavid Howells 			parent_vnode->fid.unique);
51b134d687SDavid Howells 
52b134d687SDavid Howells 	if (!test_and_set_bit(0, &once_only))
53b134d687SDavid Howells 		dump_stack();
54b134d687SDavid Howells }
55b134d687SDavid Howells 
561da177e4SLinus Torvalds /*
57bc899ee1SDavid Howells  * Set parameters for the netfs library
58bc899ee1SDavid Howells  */
afs_set_netfs_context(struct afs_vnode * vnode)59bc899ee1SDavid Howells static void afs_set_netfs_context(struct afs_vnode *vnode)
60bc899ee1SDavid Howells {
61e81fb419SLinus Torvalds 	netfs_inode_init(&vnode->netfs, &afs_req_ops);
62bc899ee1SDavid Howells }
63bc899ee1SDavid Howells 
64bc899ee1SDavid Howells /*
65dd9fbcb8SDavid Howells  * Initialise an inode from the vnode status.
661da177e4SLinus Torvalds  */
afs_inode_init_from_status(struct afs_operation * op,struct afs_vnode_param * vp,struct afs_vnode * vnode)67e49c7b2fSDavid Howells static int afs_inode_init_from_status(struct afs_operation *op,
68e49c7b2fSDavid Howells 				      struct afs_vnode_param *vp,
69e49c7b2fSDavid Howells 				      struct afs_vnode *vnode)
701da177e4SLinus Torvalds {
71e49c7b2fSDavid Howells 	struct afs_file_status *status = &vp->scb.status;
721da177e4SLinus Torvalds 	struct inode *inode = AFS_VNODE_TO_I(vnode);
73a58823acSDavid Howells 	struct timespec64 t;
741da177e4SLinus Torvalds 
75e49c7b2fSDavid Howells 	_enter("{%llx:%llu.%u} %s",
76e49c7b2fSDavid Howells 	       vp->fid.vid, vp->fid.vnode, vp->fid.unique,
77e49c7b2fSDavid Howells 	       op->type ? op->type->name : "???");
78e49c7b2fSDavid Howells 
79260a9803SDavid Howells 	_debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
80a58823acSDavid Howells 	       status->type,
81a58823acSDavid Howells 	       status->nlink,
82a58823acSDavid Howells 	       (unsigned long long) status->size,
83a58823acSDavid Howells 	       status->data_version,
84a58823acSDavid Howells 	       status->mode);
851da177e4SLinus Torvalds 
86a58823acSDavid Howells 	write_seqlock(&vnode->cb_lock);
87c435ee34SDavid Howells 
88e49c7b2fSDavid Howells 	vnode->cb_v_break = op->cb_v_break;
89e49c7b2fSDavid Howells 	vnode->cb_s_break = op->cb_s_break;
90a58823acSDavid Howells 	vnode->status = *status;
91dd9fbcb8SDavid Howells 
92a58823acSDavid Howells 	t = status->mtime_client;
93b9170a28SJeff Layton 	inode_set_ctime_to_ts(inode, t);
94a58823acSDavid Howells 	inode->i_mtime = t;
95a58823acSDavid Howells 	inode->i_atime = t;
96e49c7b2fSDavid Howells 	inode->i_flags |= S_NOATIME;
97a58823acSDavid Howells 	inode->i_uid = make_kuid(&init_user_ns, status->owner);
98a58823acSDavid Howells 	inode->i_gid = make_kgid(&init_user_ns, status->group);
99874c8ca1SDavid Howells 	set_nlink(&vnode->netfs.inode, status->nlink);
100a58823acSDavid Howells 
101a58823acSDavid Howells 	switch (status->type) {
1021da177e4SLinus Torvalds 	case AFS_FTYPE_FILE:
1036e1eb04aSDavid Howells 		inode->i_mode	= S_IFREG | (status->mode & S_IALLUGO);
1041da177e4SLinus Torvalds 		inode->i_op	= &afs_file_inode_operations;
10500d3b7a4SDavid Howells 		inode->i_fop	= &afs_file_operations;
10675bd228dSDavid Howells 		inode->i_mapping->a_ops	= &afs_file_aops;
1078549a263SDavid Howells 		mapping_set_large_folios(inode->i_mapping);
1081da177e4SLinus Torvalds 		break;
1091da177e4SLinus Torvalds 	case AFS_FTYPE_DIR:
1106e1eb04aSDavid Howells 		inode->i_mode	= S_IFDIR |  (status->mode & S_IALLUGO);
1111da177e4SLinus Torvalds 		inode->i_op	= &afs_dir_inode_operations;
1121da177e4SLinus Torvalds 		inode->i_fop	= &afs_dir_file_operations;
113f3ddee8dSDavid Howells 		inode->i_mapping->a_ops	= &afs_dir_aops;
1148549a263SDavid Howells 		mapping_set_large_folios(inode->i_mapping);
1151da177e4SLinus Torvalds 		break;
1161da177e4SLinus Torvalds 	case AFS_FTYPE_SYMLINK:
117944c74f4SDavid Howells 		/* Symlinks with a mode of 0644 are actually mountpoints. */
118a58823acSDavid Howells 		if ((status->mode & 0777) == 0644) {
119944c74f4SDavid Howells 			inode->i_flags |= S_AUTOMOUNT;
120944c74f4SDavid Howells 
121944c74f4SDavid Howells 			set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
122944c74f4SDavid Howells 
123944c74f4SDavid Howells 			inode->i_mode	= S_IFDIR | 0555;
124944c74f4SDavid Howells 			inode->i_op	= &afs_mntpt_inode_operations;
125944c74f4SDavid Howells 			inode->i_fop	= &afs_mntpt_file_operations;
12675bd228dSDavid Howells 			inode->i_mapping->a_ops	= &afs_symlink_aops;
127944c74f4SDavid Howells 		} else {
128a58823acSDavid Howells 			inode->i_mode	= S_IFLNK | status->mode;
129d3e3b7eaSDavid Howells 			inode->i_op	= &afs_symlink_inode_operations;
13075bd228dSDavid Howells 			inode->i_mapping->a_ops	= &afs_symlink_aops;
131944c74f4SDavid Howells 		}
13221fc61c7SAl Viro 		inode_nohighmem(inode);
1331da177e4SLinus Torvalds 		break;
1341da177e4SLinus Torvalds 	default:
135e49c7b2fSDavid Howells 		dump_vnode(vnode, op->file[0].vnode != vnode ? op->file[0].vnode : NULL);
136a58823acSDavid Howells 		write_sequnlock(&vnode->cb_lock);
1377126ead9SDavid Howells 		return afs_protocol_error(NULL, afs_eproto_file_type);
1381da177e4SLinus Torvalds 	}
1391da177e4SLinus Torvalds 
1402cd42d19SDavid Howells 	afs_set_i_size(vnode, status->size);
141bc899ee1SDavid Howells 	afs_set_netfs_context(vnode);
142c435ee34SDavid Howells 
143a58823acSDavid Howells 	vnode->invalid_before	= status->data_version;
144874c8ca1SDavid Howells 	inode_set_iversion_raw(&vnode->netfs.inode, status->data_version);
145a58823acSDavid Howells 
146e49c7b2fSDavid Howells 	if (!vp->scb.have_cb) {
147a58823acSDavid Howells 		/* it's a symlink we just created (the fileserver
148a58823acSDavid Howells 		 * didn't give us a callback) */
149a58823acSDavid Howells 		vnode->cb_expires_at = ktime_get_real_seconds();
150a58823acSDavid Howells 	} else {
151e49c7b2fSDavid Howells 		vnode->cb_expires_at = vp->scb.callback.expires_at;
15220325960SDavid Howells 		vnode->cb_server = op->server;
153a58823acSDavid Howells 		set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
154a58823acSDavid Howells 	}
155a58823acSDavid Howells 
156a58823acSDavid Howells 	write_sequnlock(&vnode->cb_lock);
1571da177e4SLinus Torvalds 	return 0;
158ec26815aSDavid Howells }
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds /*
161a58823acSDavid Howells  * Update the core inode struct from a returned status record.
162a58823acSDavid Howells  */
afs_apply_status(struct afs_operation * op,struct afs_vnode_param * vp)163e49c7b2fSDavid Howells static void afs_apply_status(struct afs_operation *op,
164e49c7b2fSDavid Howells 			     struct afs_vnode_param *vp)
165a58823acSDavid Howells {
166e49c7b2fSDavid Howells 	struct afs_file_status *status = &vp->scb.status;
167e49c7b2fSDavid Howells 	struct afs_vnode *vnode = vp->vnode;
168874c8ca1SDavid Howells 	struct inode *inode = &vnode->netfs.inode;
169a58823acSDavid Howells 	struct timespec64 t;
170a58823acSDavid Howells 	umode_t mode;
171a58823acSDavid Howells 	bool data_changed = false;
172793fe82eSDavid Howells 	bool change_size = vp->set_size;
173a58823acSDavid Howells 
174e49c7b2fSDavid Howells 	_enter("{%llx:%llu.%u} %s",
175e49c7b2fSDavid Howells 	       vp->fid.vid, vp->fid.vnode, vp->fid.unique,
176e49c7b2fSDavid Howells 	       op->type ? op->type->name : "???");
177e49c7b2fSDavid Howells 
178a58823acSDavid Howells 	BUG_ON(test_bit(AFS_VNODE_UNSET, &vnode->flags));
179a58823acSDavid Howells 
180a58823acSDavid Howells 	if (status->type != vnode->status.type) {
181a4e530aeSKefeng Wang 		pr_warn("Vnode %llx:%llx:%x changed type %u to %u\n",
182a58823acSDavid Howells 			vnode->fid.vid,
183a58823acSDavid Howells 			vnode->fid.vnode,
184a58823acSDavid Howells 			vnode->fid.unique,
185a58823acSDavid Howells 			status->type, vnode->status.type);
1867126ead9SDavid Howells 		afs_protocol_error(NULL, afs_eproto_bad_status);
187a58823acSDavid Howells 		return;
188a58823acSDavid Howells 	}
189a58823acSDavid Howells 
190a58823acSDavid Howells 	if (status->nlink != vnode->status.nlink)
191da8d0755SDavid Howells 		set_nlink(inode, status->nlink);
192a58823acSDavid Howells 
193a58823acSDavid Howells 	if (status->owner != vnode->status.owner)
194da8d0755SDavid Howells 		inode->i_uid = make_kuid(&init_user_ns, status->owner);
195a58823acSDavid Howells 
196a58823acSDavid Howells 	if (status->group != vnode->status.group)
197da8d0755SDavid Howells 		inode->i_gid = make_kgid(&init_user_ns, status->group);
198a58823acSDavid Howells 
199a58823acSDavid Howells 	if (status->mode != vnode->status.mode) {
200da8d0755SDavid Howells 		mode = inode->i_mode;
201a58823acSDavid Howells 		mode &= ~S_IALLUGO;
2026e1eb04aSDavid Howells 		mode |= status->mode & S_IALLUGO;
203da8d0755SDavid Howells 		WRITE_ONCE(inode->i_mode, mode);
204a58823acSDavid Howells 	}
205a58823acSDavid Howells 
206a58823acSDavid Howells 	t = status->mtime_client;
207da8d0755SDavid Howells 	inode->i_mtime = t;
208da8d0755SDavid Howells 	if (vp->update_ctime)
209b9170a28SJeff Layton 		inode_set_ctime_to_ts(inode, op->ctime);
210a58823acSDavid Howells 
211a58823acSDavid Howells 	if (vnode->status.data_version != status->data_version)
212a58823acSDavid Howells 		data_changed = true;
213a58823acSDavid Howells 
214a58823acSDavid Howells 	vnode->status = *status;
215a58823acSDavid Howells 
216e49c7b2fSDavid Howells 	if (vp->dv_before + vp->dv_delta != status->data_version) {
2173647e42bSDavid Howells 		if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags))
218f015cf1dSDavid Howells 			pr_warn("kAFS: vnode modified {%llx:%llu} %llx->%llx %s (op=%x)\n",
219a58823acSDavid Howells 				vnode->fid.vid, vnode->fid.vnode,
220e49c7b2fSDavid Howells 				(unsigned long long)vp->dv_before + vp->dv_delta,
2213647e42bSDavid Howells 				(unsigned long long)status->data_version,
222f015cf1dSDavid Howells 				op->type ? op->type->name : "???",
223f015cf1dSDavid Howells 				op->debug_id);
2243647e42bSDavid Howells 
225a58823acSDavid Howells 		vnode->invalid_before = status->data_version;
226a58823acSDavid Howells 		if (vnode->status.type == AFS_FTYPE_DIR) {
227a58823acSDavid Howells 			if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
228a58823acSDavid Howells 				afs_stat_v(vnode, n_inval);
229a58823acSDavid Howells 		} else {
230a58823acSDavid Howells 			set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
231a58823acSDavid Howells 		}
2323f4aa981SDavid Howells 		change_size = true;
233d7f74e9aSMarc Dionne 		data_changed = true;
234a58823acSDavid Howells 	} else if (vnode->status.type == AFS_FTYPE_DIR) {
235a58823acSDavid Howells 		/* Expected directory change is handled elsewhere so
236a58823acSDavid Howells 		 * that we can locally edit the directory and save on a
237a58823acSDavid Howells 		 * download.
238a58823acSDavid Howells 		 */
239a58823acSDavid Howells 		if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
240a58823acSDavid Howells 			data_changed = false;
2413f4aa981SDavid Howells 		change_size = true;
242a58823acSDavid Howells 	}
243a58823acSDavid Howells 
244a58823acSDavid Howells 	if (data_changed) {
245da8d0755SDavid Howells 		inode_set_iversion_raw(inode, status->data_version);
2463f4aa981SDavid Howells 
2473f4aa981SDavid Howells 		/* Only update the size if the data version jumped.  If the
2483f4aa981SDavid Howells 		 * file is being modified locally, then we might have our own
2493f4aa981SDavid Howells 		 * idea of what the size should be that's not the same as
2503f4aa981SDavid Howells 		 * what's on the server.
2513f4aa981SDavid Howells 		 */
252874c8ca1SDavid Howells 		vnode->netfs.remote_i_size = status->size;
253da8d0755SDavid Howells 		if (change_size) {
2542cd42d19SDavid Howells 			afs_set_i_size(vnode, status->size);
255b9170a28SJeff Layton 			inode_set_ctime_to_ts(inode, t);
256da8d0755SDavid Howells 			inode->i_atime = t;
257da8d0755SDavid Howells 		}
258a58823acSDavid Howells 	}
259a58823acSDavid Howells }
260a58823acSDavid Howells 
261a58823acSDavid Howells /*
262a58823acSDavid Howells  * Apply a callback to a vnode.
263a58823acSDavid Howells  */
afs_apply_callback(struct afs_operation * op,struct afs_vnode_param * vp)264e49c7b2fSDavid Howells static void afs_apply_callback(struct afs_operation *op,
265e49c7b2fSDavid Howells 			       struct afs_vnode_param *vp)
266a58823acSDavid Howells {
267e49c7b2fSDavid Howells 	struct afs_callback *cb = &vp->scb.callback;
268e49c7b2fSDavid Howells 	struct afs_vnode *vnode = vp->vnode;
269a58823acSDavid Howells 
27020325960SDavid Howells 	if (!afs_cb_is_broken(vp->cb_break_before, vnode)) {
271a58823acSDavid Howells 		vnode->cb_expires_at	= cb->expires_at;
27220325960SDavid Howells 		vnode->cb_server	= op->server;
273a58823acSDavid Howells 		set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
274a58823acSDavid Howells 	}
275a58823acSDavid Howells }
276a58823acSDavid Howells 
277a58823acSDavid Howells /*
278a58823acSDavid Howells  * Apply the received status and callback to an inode all in the same critical
279a58823acSDavid Howells  * section to avoid races with afs_validate().
280a58823acSDavid Howells  */
afs_vnode_commit_status(struct afs_operation * op,struct afs_vnode_param * vp)281e49c7b2fSDavid Howells void afs_vnode_commit_status(struct afs_operation *op, struct afs_vnode_param *vp)
282a58823acSDavid Howells {
283e49c7b2fSDavid Howells 	struct afs_vnode *vnode = vp->vnode;
284e49c7b2fSDavid Howells 
285e49c7b2fSDavid Howells 	_enter("");
286e49c7b2fSDavid Howells 
287a58823acSDavid Howells 	write_seqlock(&vnode->cb_lock);
288a58823acSDavid Howells 
289e49c7b2fSDavid Howells 	if (vp->scb.have_error) {
290b6489a49SDavid Howells 		/* A YFS server will return this from RemoveFile2 and AFS and
291b6489a49SDavid Howells 		 * YFS will return this from InlineBulkStatus.
292b6489a49SDavid Howells 		 */
293e49c7b2fSDavid Howells 		if (vp->scb.status.abort_code == VNOVNODE) {
294a38a7558SDavid Howells 			set_bit(AFS_VNODE_DELETED, &vnode->flags);
295874c8ca1SDavid Howells 			clear_nlink(&vnode->netfs.inode);
296051d2525SDavid Howells 			__afs_break_callback(vnode, afs_cb_break_for_deleted);
297b6489a49SDavid Howells 			op->flags &= ~AFS_OPERATION_DIR_CONFLICT;
298a38a7558SDavid Howells 		}
299b6489a49SDavid Howells 	} else if (vp->scb.have_status) {
30022650f14SDavid Howells 		if (vp->speculative &&
30122650f14SDavid Howells 		    (test_bit(AFS_VNODE_MODIFYING, &vnode->flags) ||
30222650f14SDavid Howells 		     vp->dv_before != vnode->status.data_version))
303a9e5c87cSDavid Howells 			/* Ignore the result of a speculative bulk status fetch
304a9e5c87cSDavid Howells 			 * if it splits around a modification op, thereby
305a9e5c87cSDavid Howells 			 * appearing to regress the data version.
306a9e5c87cSDavid Howells 			 */
307a9e5c87cSDavid Howells 			goto out;
308e49c7b2fSDavid Howells 		afs_apply_status(op, vp);
309e49c7b2fSDavid Howells 		if (vp->scb.have_cb)
310e49c7b2fSDavid Howells 			afs_apply_callback(op, vp);
311b6489a49SDavid Howells 	} else if (vp->op_unlinked && !(op->flags & AFS_OPERATION_DIR_CONFLICT)) {
312874c8ca1SDavid Howells 		drop_nlink(&vnode->netfs.inode);
313874c8ca1SDavid Howells 		if (vnode->netfs.inode.i_nlink == 0) {
314b6489a49SDavid Howells 			set_bit(AFS_VNODE_DELETED, &vnode->flags);
315b6489a49SDavid Howells 			__afs_break_callback(vnode, afs_cb_break_for_deleted);
316b6489a49SDavid Howells 		}
317a38a7558SDavid Howells 	}
318a58823acSDavid Howells 
319a9e5c87cSDavid Howells out:
320a58823acSDavid Howells 	write_sequnlock(&vnode->cb_lock);
321a58823acSDavid Howells 
3227c295eecSDavid Howells 	if (vp->scb.have_status)
323e49c7b2fSDavid Howells 		afs_cache_permit(vnode, op->key, vp->cb_break_before, &vp->scb);
324a58823acSDavid Howells }
325a58823acSDavid Howells 
afs_fetch_status_success(struct afs_operation * op)326e49c7b2fSDavid Howells static void afs_fetch_status_success(struct afs_operation *op)
327e49c7b2fSDavid Howells {
328b6489a49SDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
329e49c7b2fSDavid Howells 	struct afs_vnode *vnode = vp->vnode;
330e49c7b2fSDavid Howells 	int ret;
331e49c7b2fSDavid Howells 
332874c8ca1SDavid Howells 	if (vnode->netfs.inode.i_state & I_NEW) {
333e49c7b2fSDavid Howells 		ret = afs_inode_init_from_status(op, vp, vnode);
334e49c7b2fSDavid Howells 		op->error = ret;
335e49c7b2fSDavid Howells 		if (ret == 0)
336e49c7b2fSDavid Howells 			afs_cache_permit(vnode, op->key, vp->cb_break_before, &vp->scb);
337e49c7b2fSDavid Howells 	} else {
338e49c7b2fSDavid Howells 		afs_vnode_commit_status(op, vp);
339e49c7b2fSDavid Howells 	}
340e49c7b2fSDavid Howells }
341e49c7b2fSDavid Howells 
342b6489a49SDavid Howells const struct afs_operation_ops afs_fetch_status_operation = {
343e49c7b2fSDavid Howells 	.issue_afs_rpc	= afs_fs_fetch_status,
344e49c7b2fSDavid Howells 	.issue_yfs_rpc	= yfs_fs_fetch_status,
345e49c7b2fSDavid Howells 	.success	= afs_fetch_status_success,
346728279a5SDavid Howells 	.aborted	= afs_check_for_remote_deletion,
347e49c7b2fSDavid Howells };
348e49c7b2fSDavid Howells 
349a58823acSDavid Howells /*
350d2ddc776SDavid Howells  * Fetch file status from the volume.
351d2ddc776SDavid Howells  */
afs_fetch_status(struct afs_vnode * vnode,struct key * key,bool is_new,afs_access_t * _caller_access)352a58823acSDavid Howells int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool is_new,
353a58823acSDavid Howells 		     afs_access_t *_caller_access)
354d2ddc776SDavid Howells {
355e49c7b2fSDavid Howells 	struct afs_operation *op;
356d2ddc776SDavid Howells 
3573b6492dfSDavid Howells 	_enter("%s,{%llx:%llu.%u,S=%lx}",
358d2ddc776SDavid Howells 	       vnode->volume->name,
359d2ddc776SDavid Howells 	       vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique,
360d2ddc776SDavid Howells 	       vnode->flags);
361d2ddc776SDavid Howells 
362e49c7b2fSDavid Howells 	op = afs_alloc_operation(key, vnode->volume);
363e49c7b2fSDavid Howells 	if (IS_ERR(op))
364e49c7b2fSDavid Howells 		return PTR_ERR(op);
365a58823acSDavid Howells 
366e49c7b2fSDavid Howells 	afs_op_set_vnode(op, 0, vnode);
367a58823acSDavid Howells 
368e49c7b2fSDavid Howells 	op->nr_files	= 1;
369e49c7b2fSDavid Howells 	op->ops		= &afs_fetch_status_operation;
370e49c7b2fSDavid Howells 	afs_begin_vnode_operation(op);
371e49c7b2fSDavid Howells 	afs_wait_for_operation(op);
372e49c7b2fSDavid Howells 
373e49c7b2fSDavid Howells 	if (_caller_access)
374e49c7b2fSDavid Howells 		*_caller_access = op->file[0].scb.status.caller_access;
375e49c7b2fSDavid Howells 	return afs_put_operation(op);
376d2ddc776SDavid Howells }
377d2ddc776SDavid Howells 
378e49c7b2fSDavid Howells /*
379e49c7b2fSDavid Howells  * ilookup() comparator
380e49c7b2fSDavid Howells  */
afs_ilookup5_test_by_fid(struct inode * inode,void * opaque)381e49c7b2fSDavid Howells int afs_ilookup5_test_by_fid(struct inode *inode, void *opaque)
382e49c7b2fSDavid Howells {
383e49c7b2fSDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
384e49c7b2fSDavid Howells 	struct afs_fid *fid = opaque;
385d2ddc776SDavid Howells 
386e49c7b2fSDavid Howells 	return (fid->vnode == vnode->fid.vnode &&
387e49c7b2fSDavid Howells 		fid->vnode_hi == vnode->fid.vnode_hi &&
388e49c7b2fSDavid Howells 		fid->unique == vnode->fid.unique);
389d2ddc776SDavid Howells }
390d2ddc776SDavid Howells 
391d2ddc776SDavid Howells /*
3921da177e4SLinus Torvalds  * iget5() comparator
3931da177e4SLinus Torvalds  */
afs_iget5_test(struct inode * inode,void * opaque)394e49c7b2fSDavid Howells static int afs_iget5_test(struct inode *inode, void *opaque)
3951da177e4SLinus Torvalds {
396e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = opaque;
397e49c7b2fSDavid Howells 	//struct afs_vnode *vnode = AFS_FS_I(inode);
3981da177e4SLinus Torvalds 
399e49c7b2fSDavid Howells 	return afs_ilookup5_test_by_fid(inode, &vp->fid);
400bec5eb61Swanglei }
401bec5eb61Swanglei 
402bec5eb61Swanglei /*
4031da177e4SLinus Torvalds  * iget5() inode initialiser
4041da177e4SLinus Torvalds  */
afs_iget5_set(struct inode * inode,void * opaque)4051da177e4SLinus Torvalds static int afs_iget5_set(struct inode *inode, void *opaque)
4061da177e4SLinus Torvalds {
407e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = opaque;
408e49c7b2fSDavid Howells 	struct afs_super_info *as = AFS_FS_S(inode->i_sb);
4091da177e4SLinus Torvalds 	struct afs_vnode *vnode = AFS_FS_I(inode);
4101da177e4SLinus Torvalds 
411e49c7b2fSDavid Howells 	vnode->volume		= as->volume;
412e49c7b2fSDavid Howells 	vnode->fid		= vp->fid;
4131da177e4SLinus Torvalds 
4143b6492dfSDavid Howells 	/* YFS supports 96-bit vnode IDs, but Linux only supports
4153b6492dfSDavid Howells 	 * 64-bit inode numbers.
4163b6492dfSDavid Howells 	 */
417e49c7b2fSDavid Howells 	inode->i_ino		= vnode->fid.vnode;
418e49c7b2fSDavid Howells 	inode->i_generation	= vnode->fid.unique;
4191da177e4SLinus Torvalds 	return 0;
420ec26815aSDavid Howells }
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds /*
423402cb8ddSDavid Howells  * Get a cache cookie for an inode.
424402cb8ddSDavid Howells  */
afs_get_inode_cache(struct afs_vnode * vnode)425402cb8ddSDavid Howells static void afs_get_inode_cache(struct afs_vnode *vnode)
426402cb8ddSDavid Howells {
427402cb8ddSDavid Howells #ifdef CONFIG_AFS_FSCACHE
428402cb8ddSDavid Howells 	struct {
429523d27cdSDavid Howells 		__be32 vnode_id;
430523d27cdSDavid Howells 		__be32 unique;
431523d27cdSDavid Howells 		__be32 vnode_id_ext[2];	/* Allow for a 96-bit key */
432402cb8ddSDavid Howells 	} __packed key;
433402cb8ddSDavid Howells 	struct afs_vnode_cache_aux aux;
434402cb8ddSDavid Howells 
43503ffae90SDavid Howells 	if (vnode->status.type != AFS_FTYPE_FILE) {
436874c8ca1SDavid Howells 		vnode->netfs.cache = NULL;
437f3ddee8dSDavid Howells 		return;
438f3ddee8dSDavid Howells 	}
439f3ddee8dSDavid Howells 
440523d27cdSDavid Howells 	key.vnode_id		= htonl(vnode->fid.vnode);
441523d27cdSDavid Howells 	key.unique		= htonl(vnode->fid.unique);
442523d27cdSDavid Howells 	key.vnode_id_ext[0]	= htonl(vnode->fid.vnode >> 32);
443523d27cdSDavid Howells 	key.vnode_id_ext[1]	= htonl(vnode->fid.vnode_hi);
444523d27cdSDavid Howells 	afs_set_cache_aux(vnode, &aux);
445402cb8ddSDavid Howells 
446bc899ee1SDavid Howells 	afs_vnode_set_cache(vnode,
447bc899ee1SDavid Howells 			    fscache_acquire_cookie(
448523d27cdSDavid Howells 				    vnode->volume->cache,
449bc899ee1SDavid Howells 				    vnode->status.type == AFS_FTYPE_FILE ?
450bc899ee1SDavid Howells 				    0 : FSCACHE_ADV_SINGLE_CHUNK,
451402cb8ddSDavid Howells 				    &key, sizeof(key),
452402cb8ddSDavid Howells 				    &aux, sizeof(aux),
45345f66fa0SDavid Howells 				    i_size_read(&vnode->netfs.inode)));
454402cb8ddSDavid Howells #endif
455402cb8ddSDavid Howells }
456402cb8ddSDavid Howells 
457402cb8ddSDavid Howells /*
4581da177e4SLinus Torvalds  * inode retrieval
4591da177e4SLinus Torvalds  */
afs_iget(struct afs_operation * op,struct afs_vnode_param * vp)460e49c7b2fSDavid Howells struct inode *afs_iget(struct afs_operation *op, struct afs_vnode_param *vp)
4611da177e4SLinus Torvalds {
462e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
463874c8ca1SDavid Howells 	struct super_block *sb = dvp->vnode->netfs.inode.i_sb;
4641da177e4SLinus Torvalds 	struct afs_vnode *vnode;
4651da177e4SLinus Torvalds 	struct inode *inode;
4661da177e4SLinus Torvalds 	int ret;
4671da177e4SLinus Torvalds 
468e49c7b2fSDavid Howells 	_enter(",{%llx:%llu.%u},,", vp->fid.vid, vp->fid.vnode, vp->fid.unique);
4691da177e4SLinus Torvalds 
470e49c7b2fSDavid Howells 	inode = iget5_locked(sb, vp->fid.vnode, afs_iget5_test, afs_iget5_set, vp);
4711da177e4SLinus Torvalds 	if (!inode) {
4721da177e4SLinus Torvalds 		_leave(" = -ENOMEM");
47308e0e7c8SDavid Howells 		return ERR_PTR(-ENOMEM);
4741da177e4SLinus Torvalds 	}
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds 	vnode = AFS_FS_I(inode);
4771da177e4SLinus Torvalds 
478e49c7b2fSDavid Howells 	_debug("GOT INODE %p { vl=%llx vn=%llx, u=%x }",
479e49c7b2fSDavid Howells 	       inode, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
480e49c7b2fSDavid Howells 
4811da177e4SLinus Torvalds 	/* deal with an existing inode */
4821da177e4SLinus Torvalds 	if (!(inode->i_state & I_NEW)) {
48308e0e7c8SDavid Howells 		_leave(" = %p", inode);
48408e0e7c8SDavid Howells 		return inode;
4851da177e4SLinus Torvalds 	}
4861da177e4SLinus Torvalds 
487e49c7b2fSDavid Howells 	ret = afs_inode_init_from_status(op, vp, vnode);
48808e0e7c8SDavid Howells 	if (ret < 0)
48908e0e7c8SDavid Howells 		goto bad_inode;
4901da177e4SLinus Torvalds 
4915800db81SDavid Howells 	afs_get_inode_cache(vnode);
4925800db81SDavid Howells 
4931da177e4SLinus Torvalds 	/* success */
494260a9803SDavid Howells 	clear_bit(AFS_VNODE_UNSET, &vnode->flags);
4951da177e4SLinus Torvalds 	unlock_new_inode(inode);
4967c712458SDavid Howells 	_leave(" = %p", inode);
49708e0e7c8SDavid Howells 	return inode;
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds 	/* failure */
5001da177e4SLinus Torvalds bad_inode:
501aa7fa240SDavid Howells 	iget_failed(inode);
5021da177e4SLinus Torvalds 	_leave(" = %d [bad]", ret);
50308e0e7c8SDavid Howells 	return ERR_PTR(ret);
504ec26815aSDavid Howells }
5051da177e4SLinus Torvalds 
afs_iget5_set_root(struct inode * inode,void * opaque)506e49c7b2fSDavid Howells static int afs_iget5_set_root(struct inode *inode, void *opaque)
507e49c7b2fSDavid Howells {
508e49c7b2fSDavid Howells 	struct afs_super_info *as = AFS_FS_S(inode->i_sb);
509e49c7b2fSDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
510e49c7b2fSDavid Howells 
511e49c7b2fSDavid Howells 	vnode->volume		= as->volume;
512e49c7b2fSDavid Howells 	vnode->fid.vid		= as->volume->vid,
513e49c7b2fSDavid Howells 	vnode->fid.vnode	= 1;
514e49c7b2fSDavid Howells 	vnode->fid.unique	= 1;
515e49c7b2fSDavid Howells 	inode->i_ino		= 1;
516e49c7b2fSDavid Howells 	inode->i_generation	= 1;
517e49c7b2fSDavid Howells 	return 0;
518e49c7b2fSDavid Howells }
519e49c7b2fSDavid Howells 
520e49c7b2fSDavid Howells /*
521e49c7b2fSDavid Howells  * Set up the root inode for a volume.  This is always vnode 1, unique 1 within
522e49c7b2fSDavid Howells  * the volume.
523e49c7b2fSDavid Howells  */
afs_root_iget(struct super_block * sb,struct key * key)524e49c7b2fSDavid Howells struct inode *afs_root_iget(struct super_block *sb, struct key *key)
525e49c7b2fSDavid Howells {
526e49c7b2fSDavid Howells 	struct afs_super_info *as = AFS_FS_S(sb);
527e49c7b2fSDavid Howells 	struct afs_operation *op;
528e49c7b2fSDavid Howells 	struct afs_vnode *vnode;
529e49c7b2fSDavid Howells 	struct inode *inode;
530e49c7b2fSDavid Howells 	int ret;
531e49c7b2fSDavid Howells 
532e49c7b2fSDavid Howells 	_enter(",{%llx},,", as->volume->vid);
533e49c7b2fSDavid Howells 
534e49c7b2fSDavid Howells 	inode = iget5_locked(sb, 1, NULL, afs_iget5_set_root, NULL);
535e49c7b2fSDavid Howells 	if (!inode) {
536e49c7b2fSDavid Howells 		_leave(" = -ENOMEM");
537e49c7b2fSDavid Howells 		return ERR_PTR(-ENOMEM);
538e49c7b2fSDavid Howells 	}
539e49c7b2fSDavid Howells 
540e49c7b2fSDavid Howells 	_debug("GOT ROOT INODE %p { vl=%llx }", inode, as->volume->vid);
541e49c7b2fSDavid Howells 
542e49c7b2fSDavid Howells 	BUG_ON(!(inode->i_state & I_NEW));
543e49c7b2fSDavid Howells 
544e49c7b2fSDavid Howells 	vnode = AFS_FS_I(inode);
545e49c7b2fSDavid Howells 	vnode->cb_v_break = as->volume->cb_v_break,
546bc899ee1SDavid Howells 	afs_set_netfs_context(vnode);
547e49c7b2fSDavid Howells 
548e49c7b2fSDavid Howells 	op = afs_alloc_operation(key, as->volume);
549e49c7b2fSDavid Howells 	if (IS_ERR(op)) {
550e49c7b2fSDavid Howells 		ret = PTR_ERR(op);
551e49c7b2fSDavid Howells 		goto error;
552e49c7b2fSDavid Howells 	}
553e49c7b2fSDavid Howells 
554e49c7b2fSDavid Howells 	afs_op_set_vnode(op, 0, vnode);
555e49c7b2fSDavid Howells 
556e49c7b2fSDavid Howells 	op->nr_files	= 1;
557e49c7b2fSDavid Howells 	op->ops		= &afs_fetch_status_operation;
558e49c7b2fSDavid Howells 	ret = afs_do_sync_operation(op);
559e49c7b2fSDavid Howells 	if (ret < 0)
560e49c7b2fSDavid Howells 		goto error;
561e49c7b2fSDavid Howells 
562e49c7b2fSDavid Howells 	afs_get_inode_cache(vnode);
563e49c7b2fSDavid Howells 
564e49c7b2fSDavid Howells 	clear_bit(AFS_VNODE_UNSET, &vnode->flags);
565e49c7b2fSDavid Howells 	unlock_new_inode(inode);
566e49c7b2fSDavid Howells 	_leave(" = %p", inode);
567e49c7b2fSDavid Howells 	return inode;
568e49c7b2fSDavid Howells 
569e49c7b2fSDavid Howells error:
570e49c7b2fSDavid Howells 	iget_failed(inode);
571e49c7b2fSDavid Howells 	_leave(" = %d [bad]", ret);
572e49c7b2fSDavid Howells 	return ERR_PTR(ret);
573e49c7b2fSDavid Howells }
574e49c7b2fSDavid Howells 
5751da177e4SLinus Torvalds /*
576416351f2SDavid Howells  * mark the data attached to an inode as obsolete due to a write on the server
577416351f2SDavid Howells  * - might also want to ditch all the outstanding writes and dirty pages
578416351f2SDavid Howells  */
afs_zap_data(struct afs_vnode * vnode)579c68421bbSDavid Howells static void afs_zap_data(struct afs_vnode *vnode)
580416351f2SDavid Howells {
5813b6492dfSDavid Howells 	_enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
582416351f2SDavid Howells 
583523d27cdSDavid Howells 	afs_invalidate_cache(vnode, 0);
584c1515999SDavid Howells 
585416351f2SDavid Howells 	/* nuke all the non-dirty pages that aren't locked, mapped or being
5860f300ca9SDavid Howells 	 * written back in a regular file and completely discard the pages in a
5870f300ca9SDavid Howells 	 * directory or symlink */
588874c8ca1SDavid Howells 	if (S_ISREG(vnode->netfs.inode.i_mode))
589874c8ca1SDavid Howells 		invalidate_remote_inode(&vnode->netfs.inode);
5900f300ca9SDavid Howells 	else
591874c8ca1SDavid Howells 		invalidate_inode_pages2(vnode->netfs.inode.i_mapping);
592416351f2SDavid Howells }
593416351f2SDavid Howells 
594416351f2SDavid Howells /*
5954fe6a946SDavid Howells  * Check to see if we have a server currently serving this volume and that it
5964fe6a946SDavid Howells  * hasn't been reinitialised or dropped from the list.
59720325960SDavid Howells  */
afs_check_server_good(struct afs_vnode * vnode)5984fe6a946SDavid Howells static bool afs_check_server_good(struct afs_vnode *vnode)
59920325960SDavid Howells {
6004fe6a946SDavid Howells 	struct afs_server_list *slist;
60120325960SDavid Howells 	struct afs_server *server;
6024fe6a946SDavid Howells 	bool good;
60320325960SDavid Howells 	int i;
60420325960SDavid Howells 
6054fe6a946SDavid Howells 	if (vnode->cb_fs_s_break == atomic_read(&vnode->volume->cell->fs_s_break))
6064fe6a946SDavid Howells 		return true;
6074fe6a946SDavid Howells 
6084fe6a946SDavid Howells 	rcu_read_lock();
6094fe6a946SDavid Howells 
6104fe6a946SDavid Howells 	slist = rcu_dereference(vnode->volume->servers);
61120325960SDavid Howells 	for (i = 0; i < slist->nr_servers; i++) {
61220325960SDavid Howells 		server = slist->servers[i].server;
61320325960SDavid Howells 		if (server == vnode->cb_server) {
6144fe6a946SDavid Howells 			good = (vnode->cb_s_break == server->cb_s_break);
6154fe6a946SDavid Howells 			rcu_read_unlock();
6164fe6a946SDavid Howells 			return good;
61720325960SDavid Howells 		}
61820325960SDavid Howells 	}
61920325960SDavid Howells 
6204fe6a946SDavid Howells 	rcu_read_unlock();
62120325960SDavid Howells 	return false;
62220325960SDavid Howells }
62320325960SDavid Howells 
62420325960SDavid Howells /*
625c925bd0aSDavid Howells  * Check the validity of a vnode/inode.
626260a9803SDavid Howells  */
afs_check_validity(struct afs_vnode * vnode)627c925bd0aSDavid Howells bool afs_check_validity(struct afs_vnode *vnode)
628260a9803SDavid Howells {
629051d2525SDavid Howells 	enum afs_cb_break_reason need_clear = afs_cb_break_no_break;
630c435ee34SDavid Howells 	time64_t now = ktime_get_real_seconds();
6314fe6a946SDavid Howells 	unsigned int cb_break;
632f642404aSDavid Howells 	int seq = 0;
633260a9803SDavid Howells 
634f642404aSDavid Howells 	do {
635f642404aSDavid Howells 		read_seqbegin_or_lock(&vnode->cb_lock, &seq);
636f642404aSDavid Howells 		cb_break = vnode->cb_break;
637c435ee34SDavid Howells 
6384fe6a946SDavid Howells 		if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
6394fe6a946SDavid Howells 			if (vnode->cb_v_break != vnode->volume->cb_v_break)
6404fe6a946SDavid Howells 				need_clear = afs_cb_break_for_v_break;
6414fe6a946SDavid Howells 			else if (!afs_check_server_good(vnode))
6424fe6a946SDavid Howells 				need_clear = afs_cb_break_for_s_reinit;
6434fe6a946SDavid Howells 			else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
644051d2525SDavid Howells 				need_clear = afs_cb_break_for_zap;
6454fe6a946SDavid Howells 			else if (vnode->cb_expires_at - 10 <= now)
646051d2525SDavid Howells 				need_clear = afs_cb_break_for_lapsed;
647c435ee34SDavid Howells 		} else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
6484fe6a946SDavid Howells 			;
649ae3b7361SDavid Howells 		} else {
6504fe6a946SDavid Howells 			need_clear = afs_cb_break_no_promise;
651260a9803SDavid Howells 		}
652260a9803SDavid Howells 
653f642404aSDavid Howells 	} while (need_seqretry(&vnode->cb_lock, seq));
654f642404aSDavid Howells 
655f642404aSDavid Howells 	done_seqretry(&vnode->cb_lock, seq);
65661c347baSDavid Howells 
6574fe6a946SDavid Howells 	if (need_clear == afs_cb_break_no_break)
6584fe6a946SDavid Howells 		return true;
6594fe6a946SDavid Howells 
66061c347baSDavid Howells 	write_seqlock(&vnode->cb_lock);
6614fe6a946SDavid Howells 	if (need_clear == afs_cb_break_no_promise)
6624fe6a946SDavid Howells 		vnode->cb_v_break = vnode->volume->cb_v_break;
6634fe6a946SDavid Howells 	else if (cb_break == vnode->cb_break)
664051d2525SDavid Howells 		__afs_break_callback(vnode, need_clear);
665051d2525SDavid Howells 	else
666051d2525SDavid Howells 		trace_afs_cb_miss(&vnode->fid, need_clear);
66761c347baSDavid Howells 	write_sequnlock(&vnode->cb_lock);
6684fe6a946SDavid Howells 	return false;
669c925bd0aSDavid Howells }
670c925bd0aSDavid Howells 
671c925bd0aSDavid Howells /*
6720050d7f5SMatthew Wilcox (Oracle)  * Returns true if the pagecache is still valid.  Does not sleep.
6730050d7f5SMatthew Wilcox (Oracle)  */
afs_pagecache_valid(struct afs_vnode * vnode)6740050d7f5SMatthew Wilcox (Oracle) bool afs_pagecache_valid(struct afs_vnode *vnode)
6750050d7f5SMatthew Wilcox (Oracle) {
6760050d7f5SMatthew Wilcox (Oracle) 	if (unlikely(test_bit(AFS_VNODE_DELETED, &vnode->flags))) {
6770050d7f5SMatthew Wilcox (Oracle) 		if (vnode->netfs.inode.i_nlink)
6780050d7f5SMatthew Wilcox (Oracle) 			clear_nlink(&vnode->netfs.inode);
6790050d7f5SMatthew Wilcox (Oracle) 		return true;
6800050d7f5SMatthew Wilcox (Oracle) 	}
6810050d7f5SMatthew Wilcox (Oracle) 
6820050d7f5SMatthew Wilcox (Oracle) 	if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags) &&
6830050d7f5SMatthew Wilcox (Oracle) 	    afs_check_validity(vnode))
6840050d7f5SMatthew Wilcox (Oracle) 		return true;
6850050d7f5SMatthew Wilcox (Oracle) 
6860050d7f5SMatthew Wilcox (Oracle) 	return false;
6870050d7f5SMatthew Wilcox (Oracle) }
6880050d7f5SMatthew Wilcox (Oracle) 
6890050d7f5SMatthew Wilcox (Oracle) /*
690c925bd0aSDavid Howells  * validate a vnode/inode
691c925bd0aSDavid Howells  * - there are several things we need to check
692c925bd0aSDavid Howells  *   - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
693c925bd0aSDavid Howells  *     symlink)
694c925bd0aSDavid Howells  *   - parent dir metadata changed (security changes)
695c925bd0aSDavid Howells  *   - dentry data changed (write, truncate)
696c925bd0aSDavid Howells  *   - dentry metadata changed (security changes)
697c925bd0aSDavid Howells  */
afs_validate(struct afs_vnode * vnode,struct key * key)698c925bd0aSDavid Howells int afs_validate(struct afs_vnode *vnode, struct key *key)
699c925bd0aSDavid Howells {
700c925bd0aSDavid Howells 	int ret;
701c925bd0aSDavid Howells 
702c925bd0aSDavid Howells 	_enter("{v={%llx:%llu} fl=%lx},%x",
703c925bd0aSDavid Howells 	       vnode->fid.vid, vnode->fid.vnode, vnode->flags,
704c925bd0aSDavid Howells 	       key_serial(key));
705c925bd0aSDavid Howells 
7060050d7f5SMatthew Wilcox (Oracle) 	if (afs_pagecache_valid(vnode))
707260a9803SDavid Howells 		goto valid;
708260a9803SDavid Howells 
709b61f7dcfSDavid Howells 	down_write(&vnode->validate_lock);
710260a9803SDavid Howells 
711260a9803SDavid Howells 	/* if the promise has expired, we need to check the server again to get
712260a9803SDavid Howells 	 * a new promise - note that if the (parent) directory's metadata was
713260a9803SDavid Howells 	 * changed then the security may be different and we may no longer have
714260a9803SDavid Howells 	 * access */
715c435ee34SDavid Howells 	if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
716260a9803SDavid Howells 		_debug("not promised");
717a58823acSDavid Howells 		ret = afs_fetch_status(vnode, key, false, NULL);
718c435ee34SDavid Howells 		if (ret < 0) {
719c435ee34SDavid Howells 			if (ret == -ENOENT) {
720c435ee34SDavid Howells 				set_bit(AFS_VNODE_DELETED, &vnode->flags);
721c435ee34SDavid Howells 				ret = -ESTALE;
722c435ee34SDavid Howells 			}
723260a9803SDavid Howells 			goto error_unlock;
724c435ee34SDavid Howells 		}
725260a9803SDavid Howells 		_debug("new promise [fl=%lx]", vnode->flags);
726260a9803SDavid Howells 	}
727260a9803SDavid Howells 
728260a9803SDavid Howells 	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
729260a9803SDavid Howells 		_debug("file already deleted");
730260a9803SDavid Howells 		ret = -ESTALE;
731260a9803SDavid Howells 		goto error_unlock;
732260a9803SDavid Howells 	}
733260a9803SDavid Howells 
734260a9803SDavid Howells 	/* if the vnode's data version number changed then its contents are
735260a9803SDavid Howells 	 * different */
736416351f2SDavid Howells 	if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
737416351f2SDavid Howells 		afs_zap_data(vnode);
738b61f7dcfSDavid Howells 	up_write(&vnode->validate_lock);
739260a9803SDavid Howells valid:
740260a9803SDavid Howells 	_leave(" = 0");
741260a9803SDavid Howells 	return 0;
742260a9803SDavid Howells 
743260a9803SDavid Howells error_unlock:
744b61f7dcfSDavid Howells 	up_write(&vnode->validate_lock);
745260a9803SDavid Howells 	_leave(" = %d", ret);
746260a9803SDavid Howells 	return ret;
747260a9803SDavid Howells }
748260a9803SDavid Howells 
749260a9803SDavid Howells /*
7501da177e4SLinus Torvalds  * read the attributes of an inode
7511da177e4SLinus Torvalds  */
afs_getattr(struct mnt_idmap * idmap,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int query_flags)752b74d24f7SChristian Brauner int afs_getattr(struct mnt_idmap *idmap, const struct path *path,
753549c7297SChristian Brauner 		struct kstat *stat, u32 request_mask, unsigned int query_flags)
7541da177e4SLinus Torvalds {
755a528d35eSDavid Howells 	struct inode *inode = d_inode(path->dentry);
756c435ee34SDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
7572aeb8c86SDavid Howells 	struct key *key;
7582aeb8c86SDavid Howells 	int ret, seq = 0;
7591da177e4SLinus Torvalds 
760d6e43f75SDavid Howells 	_enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation);
7611da177e4SLinus Torvalds 
762cb78d1b5SDavid Howells 	if (vnode->volume &&
763cb78d1b5SDavid Howells 	    !(query_flags & AT_STATX_DONT_SYNC) &&
7642aeb8c86SDavid Howells 	    !test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
7652aeb8c86SDavid Howells 		key = afs_request_key(vnode->volume->cell);
7662aeb8c86SDavid Howells 		if (IS_ERR(key))
7672aeb8c86SDavid Howells 			return PTR_ERR(key);
7682aeb8c86SDavid Howells 		ret = afs_validate(vnode, key);
7692aeb8c86SDavid Howells 		key_put(key);
7702aeb8c86SDavid Howells 		if (ret < 0)
7712aeb8c86SDavid Howells 			return ret;
7722aeb8c86SDavid Howells 	}
7732aeb8c86SDavid Howells 
774c435ee34SDavid Howells 	do {
775c435ee34SDavid Howells 		read_seqbegin_or_lock(&vnode->cb_lock, &seq);
776*0d72b928SJeff Layton 		generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
777b6489a49SDavid Howells 		if (test_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags) &&
778b6489a49SDavid Howells 		    stat->nlink > 0)
779b6489a49SDavid Howells 			stat->nlink -= 1;
78045f66fa0SDavid Howells 
78145f66fa0SDavid Howells 		/* Lie about the size of directories.  We maintain a locally
78245f66fa0SDavid Howells 		 * edited copy and may make different allocation decisions on
78345f66fa0SDavid Howells 		 * it, but we need to give userspace the server's size.
78445f66fa0SDavid Howells 		 */
78545f66fa0SDavid Howells 		if (S_ISDIR(inode->i_mode))
78645f66fa0SDavid Howells 			stat->size = vnode->netfs.remote_i_size;
787c435ee34SDavid Howells 	} while (need_seqretry(&vnode->cb_lock, seq));
788c435ee34SDavid Howells 
789c435ee34SDavid Howells 	done_seqretry(&vnode->cb_lock, seq);
7901da177e4SLinus Torvalds 	return 0;
791ec26815aSDavid Howells }
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds /*
794bec5eb61Swanglei  * discard an AFS inode
795bec5eb61Swanglei  */
afs_drop_inode(struct inode * inode)796bec5eb61Swanglei int afs_drop_inode(struct inode *inode)
797bec5eb61Swanglei {
798bec5eb61Swanglei 	_enter("");
799bec5eb61Swanglei 
800bec5eb61Swanglei 	if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags))
801bec5eb61Swanglei 		return generic_delete_inode(inode);
802bec5eb61Swanglei 	else
803bec5eb61Swanglei 		return generic_drop_inode(inode);
804bec5eb61Swanglei }
805bec5eb61Swanglei 
806bec5eb61Swanglei /*
8071da177e4SLinus Torvalds  * clear an AFS inode
8081da177e4SLinus Torvalds  */
afs_evict_inode(struct inode * inode)809b57922d9SAl Viro void afs_evict_inode(struct inode *inode)
8101da177e4SLinus Torvalds {
811c7f75ef3SDavid Howells 	struct afs_vnode_cache_aux aux;
812c7f75ef3SDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
8131da177e4SLinus Torvalds 
8143b6492dfSDavid Howells 	_enter("{%llx:%llu.%d}",
815260a9803SDavid Howells 	       vnode->fid.vid,
8161da177e4SLinus Torvalds 	       vnode->fid.vnode,
817c435ee34SDavid Howells 	       vnode->fid.unique);
8181da177e4SLinus Torvalds 
81908e0e7c8SDavid Howells 	_debug("CLEAR INODE %p", inode);
8201da177e4SLinus Torvalds 
82108e0e7c8SDavid Howells 	ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
82208e0e7c8SDavid Howells 
82391b0abe3SJohannes Weiner 	truncate_inode_pages_final(&inode->i_data);
824c7f75ef3SDavid Howells 
825c7f75ef3SDavid Howells 	afs_set_cache_aux(vnode, &aux);
826c7f75ef3SDavid Howells 	fscache_clear_inode_writeback(afs_vnode_cache(vnode), inode, &aux);
827dbd5768fSJan Kara 	clear_inode(inode);
828b57922d9SAl Viro 
8294343d008SDavid Howells 	while (!list_empty(&vnode->wb_keys)) {
8304343d008SDavid Howells 		struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next,
8314343d008SDavid Howells 						    struct afs_wb_key, vnode_link);
8324343d008SDavid Howells 		list_del(&wbk->vnode_link);
8334343d008SDavid Howells 		afs_put_wb_key(wbk);
8344343d008SDavid Howells 	}
8351da177e4SLinus Torvalds 
836bc899ee1SDavid Howells 	fscache_relinquish_cookie(afs_vnode_cache(vnode),
837678edd09SDavid Howells 				  test_bit(AFS_VNODE_DELETED, &vnode->flags));
8381da177e4SLinus Torvalds 
839a1b879eeSDavid Howells 	afs_prune_wb_keys(vnode);
840fe342cf7SDavid Howells 	afs_put_permits(rcu_access_pointer(vnode->permit_cache));
84179ddbfa5SDavid Howells 	key_put(vnode->silly_key);
84279ddbfa5SDavid Howells 	vnode->silly_key = NULL;
84359d49076SDavid Howells 	key_put(vnode->lock_key);
84459d49076SDavid Howells 	vnode->lock_key = NULL;
8451da177e4SLinus Torvalds 	_leave("");
846ec26815aSDavid Howells }
84731143d5dSDavid Howells 
afs_setattr_success(struct afs_operation * op)848e49c7b2fSDavid Howells static void afs_setattr_success(struct afs_operation *op)
849e49c7b2fSDavid Howells {
850ec0fa0b6SDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
851874c8ca1SDavid Howells 	struct inode *inode = &vp->vnode->netfs.inode;
852ec0fa0b6SDavid Howells 	loff_t old_i_size = i_size_read(inode);
853793fe82eSDavid Howells 
854ec0fa0b6SDavid Howells 	op->setattr.old_i_size = old_i_size;
855ec0fa0b6SDavid Howells 	afs_vnode_commit_status(op, vp);
856ec0fa0b6SDavid Howells 	/* inode->i_size has now been changed. */
857ec0fa0b6SDavid Howells 
858793fe82eSDavid Howells 	if (op->setattr.attr->ia_valid & ATTR_SIZE) {
859ec0fa0b6SDavid Howells 		loff_t size = op->setattr.attr->ia_size;
860ec0fa0b6SDavid Howells 		if (size > old_i_size)
861ec0fa0b6SDavid Howells 			pagecache_isize_extended(inode, old_i_size, size);
862ec0fa0b6SDavid Howells 	}
863ec0fa0b6SDavid Howells }
864ec0fa0b6SDavid Howells 
afs_setattr_edit_file(struct afs_operation * op)865ec0fa0b6SDavid Howells static void afs_setattr_edit_file(struct afs_operation *op)
866ec0fa0b6SDavid Howells {
867ec0fa0b6SDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
868874c8ca1SDavid Howells 	struct inode *inode = &vp->vnode->netfs.inode;
869ec0fa0b6SDavid Howells 
870ec0fa0b6SDavid Howells 	if (op->setattr.attr->ia_valid & ATTR_SIZE) {
871ec0fa0b6SDavid Howells 		loff_t size = op->setattr.attr->ia_size;
872ec0fa0b6SDavid Howells 		loff_t i_size = op->setattr.old_i_size;
873ec0fa0b6SDavid Howells 
874ec0fa0b6SDavid Howells 		if (size < i_size)
875793fe82eSDavid Howells 			truncate_pagecache(inode, size);
876523d27cdSDavid Howells 		if (size != i_size)
877523d27cdSDavid Howells 			fscache_resize_cookie(afs_vnode_cache(vp->vnode),
878523d27cdSDavid Howells 					      vp->scb.status.size);
879793fe82eSDavid Howells 	}
880e49c7b2fSDavid Howells }
881e49c7b2fSDavid Howells 
882e49c7b2fSDavid Howells static const struct afs_operation_ops afs_setattr_operation = {
883e49c7b2fSDavid Howells 	.issue_afs_rpc	= afs_fs_setattr,
884e49c7b2fSDavid Howells 	.issue_yfs_rpc	= yfs_fs_setattr,
885e49c7b2fSDavid Howells 	.success	= afs_setattr_success,
886ec0fa0b6SDavid Howells 	.edit_dir	= afs_setattr_edit_file,
887e49c7b2fSDavid Howells };
888e49c7b2fSDavid Howells 
88931143d5dSDavid Howells /*
89031143d5dSDavid Howells  * set the attributes of an inode
89131143d5dSDavid Howells  */
afs_setattr(struct mnt_idmap * idmap,struct dentry * dentry,struct iattr * attr)892c1632a0fSChristian Brauner int afs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
893549c7297SChristian Brauner 		struct iattr *attr)
89431143d5dSDavid Howells {
8950770bd41SDavid Howells 	const unsigned int supported =
8960770bd41SDavid Howells 		ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
8970770bd41SDavid Howells 		ATTR_MTIME | ATTR_MTIME_SET | ATTR_TIMES_SET | ATTR_TOUCH;
898e49c7b2fSDavid Howells 	struct afs_operation *op;
8992b0143b5SDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
900874c8ca1SDavid Howells 	struct inode *inode = &vnode->netfs.inode;
9010770bd41SDavid Howells 	loff_t i_size;
902793fe82eSDavid Howells 	int ret;
90331143d5dSDavid Howells 
9043b6492dfSDavid Howells 	_enter("{%llx:%llu},{n=%pd},%x",
905a455589fSAl Viro 	       vnode->fid.vid, vnode->fid.vnode, dentry,
90631143d5dSDavid Howells 	       attr->ia_valid);
90731143d5dSDavid Howells 
9080770bd41SDavid Howells 	if (!(attr->ia_valid & supported)) {
90931143d5dSDavid Howells 		_leave(" = 0 [unsupported]");
91031143d5dSDavid Howells 		return 0;
91131143d5dSDavid Howells 	}
91231143d5dSDavid Howells 
9130770bd41SDavid Howells 	i_size = i_size_read(inode);
914793fe82eSDavid Howells 	if (attr->ia_valid & ATTR_SIZE) {
9150770bd41SDavid Howells 		if (!S_ISREG(inode->i_mode))
916793fe82eSDavid Howells 			return -EISDIR;
917793fe82eSDavid Howells 
9180770bd41SDavid Howells 		ret = inode_newsize_ok(inode, attr->ia_size);
919793fe82eSDavid Howells 		if (ret)
920793fe82eSDavid Howells 			return ret;
921793fe82eSDavid Howells 
9220770bd41SDavid Howells 		if (attr->ia_size == i_size)
923793fe82eSDavid Howells 			attr->ia_valid &= ~ATTR_SIZE;
924793fe82eSDavid Howells 	}
925793fe82eSDavid Howells 
926523d27cdSDavid Howells 	fscache_use_cookie(afs_vnode_cache(vnode), true);
927523d27cdSDavid Howells 
928ec0fa0b6SDavid Howells 	/* Prevent any new writebacks from starting whilst we do this. */
929ec0fa0b6SDavid Howells 	down_write(&vnode->validate_lock);
930ec0fa0b6SDavid Howells 
9310770bd41SDavid Howells 	if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode)) {
9320770bd41SDavid Howells 		loff_t size = attr->ia_size;
9330770bd41SDavid Howells 
9340770bd41SDavid Howells 		/* Wait for any outstanding writes to the server to complete */
9350770bd41SDavid Howells 		loff_t from = min(size, i_size);
9360770bd41SDavid Howells 		loff_t to = max(size, i_size);
9370770bd41SDavid Howells 		ret = filemap_fdatawait_range(inode->i_mapping, from, to);
9380770bd41SDavid Howells 		if (ret < 0)
9390770bd41SDavid Howells 			goto out_unlock;
9400770bd41SDavid Howells 
9410770bd41SDavid Howells 		/* Don't talk to the server if we're just shortening in-memory
9420770bd41SDavid Howells 		 * writes that haven't gone to the server yet.
9430770bd41SDavid Howells 		 */
9440770bd41SDavid Howells 		if (!(attr->ia_valid & (supported & ~ATTR_SIZE & ~ATTR_MTIME)) &&
9450770bd41SDavid Howells 		    attr->ia_size < i_size &&
9460770bd41SDavid Howells 		    attr->ia_size > vnode->status.size) {
9470770bd41SDavid Howells 			truncate_pagecache(inode, attr->ia_size);
9480770bd41SDavid Howells 			fscache_resize_cookie(afs_vnode_cache(vnode),
9490770bd41SDavid Howells 					      attr->ia_size);
9500770bd41SDavid Howells 			i_size_write(inode, attr->ia_size);
9510770bd41SDavid Howells 			ret = 0;
9520770bd41SDavid Howells 			goto out_unlock;
9530770bd41SDavid Howells 		}
9540770bd41SDavid Howells 	}
9550770bd41SDavid Howells 
956e49c7b2fSDavid Howells 	op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ?
957e49c7b2fSDavid Howells 				  afs_file_key(attr->ia_file) : NULL),
958e49c7b2fSDavid Howells 				 vnode->volume);
959ec0fa0b6SDavid Howells 	if (IS_ERR(op)) {
960ec0fa0b6SDavid Howells 		ret = PTR_ERR(op);
961ec0fa0b6SDavid Howells 		goto out_unlock;
962ec0fa0b6SDavid Howells 	}
96331143d5dSDavid Howells 
964e49c7b2fSDavid Howells 	afs_op_set_vnode(op, 0, vnode);
965e49c7b2fSDavid Howells 	op->setattr.attr = attr;
966a58823acSDavid Howells 
967793fe82eSDavid Howells 	if (attr->ia_valid & ATTR_SIZE) {
968e49c7b2fSDavid Howells 		op->file[0].dv_delta = 1;
969793fe82eSDavid Howells 		op->file[0].set_size = true;
970793fe82eSDavid Howells 	}
971da8d0755SDavid Howells 	op->ctime = attr->ia_ctime;
972da8d0755SDavid Howells 	op->file[0].update_ctime = 1;
97322650f14SDavid Howells 	op->file[0].modification = true;
974a58823acSDavid Howells 
975e49c7b2fSDavid Howells 	op->ops = &afs_setattr_operation;
976ec0fa0b6SDavid Howells 	ret = afs_do_sync_operation(op);
977ec0fa0b6SDavid Howells 
978ec0fa0b6SDavid Howells out_unlock:
979ec0fa0b6SDavid Howells 	up_write(&vnode->validate_lock);
980523d27cdSDavid Howells 	fscache_unuse_cookie(afs_vnode_cache(vnode), NULL, NULL);
981ec0fa0b6SDavid Howells 	_leave(" = %d", ret);
982ec0fa0b6SDavid Howells 	return ret;
98331143d5dSDavid Howells }
984