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