blob: efacdb7c1dee59ad78e0c600e73468ea90285638 [file] [log] [blame]
David Howells08e0e7c2007-04-26 15:55:03 -07001/* AFS File Server client stubs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
David Howells08e0e7c2007-04-26 15:55:03 -07003 * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/init.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090013#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/sched.h>
David Howells08e0e7c2007-04-26 15:55:03 -070015#include <linux/circ_buf.h>
Jeff Laytona01179e2017-12-11 06:35:11 -050016#include <linux/iversion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "internal.h"
David Howells08e0e7c2007-04-26 15:55:03 -070018#include "afs_fs.h"
David Howellsdd9fbcb2018-04-06 14:17:24 +010019#include "xdr_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
David Howells025db802017-11-02 15:27:51 +000021static const struct afs_fid afs_zero_fid;
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023/*
David Howells6db3ac32017-03-16 16:27:44 +000024 * We need somewhere to discard into in case the server helpfully returns more
25 * than we asked for in FS.FetchData{,64}.
26 */
27static u8 afs_discard_buffer[64];
28
David Howellsd2ddc772017-11-02 15:27:50 +000029static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi)
David Howellsc435ee32017-11-02 15:27:49 +000030{
David Howellsd2ddc772017-11-02 15:27:50 +000031 call->cbi = afs_get_cb_interest(cbi);
David Howellsc435ee32017-11-02 15:27:49 +000032}
33
David Howells6db3ac32017-03-16 16:27:44 +000034/*
David Howells260a9802007-04-26 15:59:35 -070035 * decode an AFSFid block
36 */
37static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
38{
39 const __be32 *bp = *_bp;
40
41 fid->vid = ntohl(*bp++);
42 fid->vnode = ntohl(*bp++);
43 fid->unique = ntohl(*bp++);
44 *_bp = bp;
45}
46
47/*
David Howells888b3382018-04-06 14:17:24 +010048 * Dump a bad file status record.
49 */
50static void xdr_dump_bad(const __be32 *bp)
51{
52 __be32 x[4];
53 int i;
54
55 pr_notice("AFS XDR: Bad status record\n");
56 for (i = 0; i < 5 * 4 * 4; i += 16) {
57 memcpy(x, bp, 16);
58 bp += 4;
59 pr_notice("%03x: %08x %08x %08x %08x\n",
60 i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
61 }
62
63 memcpy(x, bp, 4);
64 pr_notice("0x50: %08x\n", ntohl(x[0]));
65}
66
67/*
David Howellsdd9fbcb2018-04-06 14:17:24 +010068 * Update the core inode struct from a returned status record.
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 */
David Howellsdd9fbcb2018-04-06 14:17:24 +010070void afs_update_inode_from_status(struct afs_vnode *vnode,
71 struct afs_file_status *status,
72 const afs_dataversion_t *expected_version,
73 u8 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074{
David Howellsdd9fbcb2018-04-06 14:17:24 +010075 struct timespec t;
David Howells08e0e7c2007-04-26 15:55:03 -070076 umode_t mode;
David Howells08e0e7c2007-04-26 15:55:03 -070077
David Howellsdd9fbcb2018-04-06 14:17:24 +010078 t.tv_sec = status->mtime_client;
79 t.tv_nsec = 0;
80 vnode->vfs_inode.i_ctime = t;
81 vnode->vfs_inode.i_mtime = t;
82 vnode->vfs_inode.i_atime = t;
David Howellsc435ee32017-11-02 15:27:49 +000083
David Howellsdd9fbcb2018-04-06 14:17:24 +010084 if (flags & (AFS_VNODE_META_CHANGED | AFS_VNODE_NOT_YET_SET)) {
85 vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner);
86 vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group);
87 set_nlink(&vnode->vfs_inode, status->nlink);
David Howells08e0e7c2007-04-26 15:55:03 -070088
David Howellsdd9fbcb2018-04-06 14:17:24 +010089 mode = vnode->vfs_inode.i_mode;
90 mode &= ~S_IALLUGO;
91 mode |= status->mode;
92 barrier();
93 vnode->vfs_inode.i_mode = mode;
David Howells888b3382018-04-06 14:17:24 +010094 }
95
David Howellsdd9fbcb2018-04-06 14:17:24 +010096 if (!(flags & AFS_VNODE_NOT_YET_SET)) {
97 if (expected_version &&
98 *expected_version != status->data_version) {
99 _debug("vnode modified %llx on {%x:%u} [exp %llx]",
100 (unsigned long long) status->data_version,
101 vnode->fid.vid, vnode->fid.vnode,
102 (unsigned long long) *expected_version);
David Howellsa4ff7402018-04-06 14:17:24 +0100103 vnode->invalid_before = status->data_version;
David Howellsf3ddee82018-04-06 14:17:25 +0100104 if (vnode->status.type == AFS_FTYPE_DIR) {
105 if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
106 afs_stat_v(vnode, n_inval);
107 } else {
108 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
109 }
David Howells63a46812018-04-06 14:17:25 +0100110 } else if (vnode->status.type == AFS_FTYPE_DIR) {
111 /* Expected directory change is handled elsewhere so
112 * that we can locally edit the directory and save on a
113 * download.
114 */
115 if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
116 flags &= ~AFS_VNODE_DATA_CHANGED;
David Howells260a9802007-04-26 15:59:35 -0700117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 }
David Howellsc435ee32017-11-02 15:27:49 +0000119
David Howellsdd9fbcb2018-04-06 14:17:24 +0100120 if (flags & (AFS_VNODE_DATA_CHANGED | AFS_VNODE_NOT_YET_SET)) {
121 inode_set_iversion_raw(&vnode->vfs_inode, status->data_version);
122 i_size_write(&vnode->vfs_inode, status->size);
123 }
124}
125
126/*
127 * decode an AFSFetchStatus block
128 */
David Howells5f702c82018-04-06 14:17:25 +0100129static int xdr_decode_AFSFetchStatus(struct afs_call *call,
130 const __be32 **_bp,
David Howellsdd9fbcb2018-04-06 14:17:24 +0100131 struct afs_file_status *status,
132 struct afs_vnode *vnode,
133 const afs_dataversion_t *expected_version,
David Howellsf3ddee82018-04-06 14:17:25 +0100134 struct afs_read *read_req)
David Howellsdd9fbcb2018-04-06 14:17:24 +0100135{
136 const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
137 u64 data_version, size;
138 u32 type, abort_code;
139 u8 flags = 0;
140 int ret;
141
142 if (vnode)
143 write_seqlock(&vnode->cb_lock);
144
145 if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
146 pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
147 goto bad;
148 }
149
150 type = ntohl(xdr->type);
151 abort_code = ntohl(xdr->abort_code);
152 switch (type) {
153 case AFS_FTYPE_FILE:
154 case AFS_FTYPE_DIR:
155 case AFS_FTYPE_SYMLINK:
156 if (type != status->type &&
157 vnode &&
158 !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
159 pr_warning("Vnode %x:%x:%x changed type %u to %u\n",
160 vnode->fid.vid,
161 vnode->fid.vnode,
162 vnode->fid.unique,
163 status->type, type);
164 goto bad;
165 }
166 status->type = type;
167 break;
168 case AFS_FTYPE_INVALID:
169 if (abort_code != 0) {
170 status->abort_code = abort_code;
David Howells5f702c82018-04-06 14:17:25 +0100171 ret = 0;
David Howellsdd9fbcb2018-04-06 14:17:24 +0100172 goto out;
173 }
174 /* Fall through */
175 default:
176 goto bad;
177 }
178
179#define EXTRACT_M(FIELD) \
180 do { \
181 u32 x = ntohl(xdr->FIELD); \
182 if (status->FIELD != x) { \
183 flags |= AFS_VNODE_META_CHANGED; \
184 status->FIELD = x; \
185 } \
186 } while (0)
187
188 EXTRACT_M(nlink);
189 EXTRACT_M(author);
190 EXTRACT_M(owner);
191 EXTRACT_M(caller_access); /* call ticket dependent */
192 EXTRACT_M(anon_access);
193 EXTRACT_M(mode);
194 EXTRACT_M(group);
195
196 status->mtime_client = ntohl(xdr->mtime_client);
197 status->mtime_server = ntohl(xdr->mtime_server);
198 status->lock_count = ntohl(xdr->lock_count);
199
200 size = (u64)ntohl(xdr->size_lo);
201 size |= (u64)ntohl(xdr->size_hi) << 32;
David Howells63a46812018-04-06 14:17:25 +0100202 status->size = size;
David Howellsdd9fbcb2018-04-06 14:17:24 +0100203
204 data_version = (u64)ntohl(xdr->data_version_lo);
205 data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
206 if (data_version != status->data_version) {
207 status->data_version = data_version;
208 flags |= AFS_VNODE_DATA_CHANGED;
209 }
David Howellsf3ddee82018-04-06 14:17:25 +0100210
211 if (read_req) {
212 read_req->data_version = data_version;
213 read_req->file_size = size;
214 }
David Howellsdd9fbcb2018-04-06 14:17:24 +0100215
216 *_bp = (const void *)*_bp + sizeof(*xdr);
217
218 if (vnode) {
219 if (test_bit(AFS_VNODE_UNSET, &vnode->flags))
220 flags |= AFS_VNODE_NOT_YET_SET;
221 afs_update_inode_from_status(vnode, status, expected_version,
222 flags);
223 }
224
225 ret = 0;
226
David Howells888b3382018-04-06 14:17:24 +0100227out:
David Howellsd2ddc772017-11-02 15:27:50 +0000228 if (vnode)
229 write_sequnlock(&vnode->cb_lock);
David Howellsdd9fbcb2018-04-06 14:17:24 +0100230 return ret;
231
232bad:
233 xdr_dump_bad(*_bp);
David Howells5f702c82018-04-06 14:17:25 +0100234 ret = afs_protocol_error(call, -EBADMSG);
David Howellsdd9fbcb2018-04-06 14:17:24 +0100235 goto out;
David Howellsec268152007-04-26 15:49:28 -0700236}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238/*
David Howells08e0e7c2007-04-26 15:55:03 -0700239 * decode an AFSCallBack block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 */
David Howellsc435ee32017-11-02 15:27:49 +0000241static void xdr_decode_AFSCallBack(struct afs_call *call,
242 struct afs_vnode *vnode,
243 const __be32 **_bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244{
David Howellsd2ddc772017-11-02 15:27:50 +0000245 struct afs_cb_interest *old, *cbi = call->cbi;
David Howells08e0e7c2007-04-26 15:55:03 -0700246 const __be32 *bp = *_bp;
David Howellsc435ee32017-11-02 15:27:49 +0000247 u32 cb_expiry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
David Howellsc435ee32017-11-02 15:27:49 +0000249 write_seqlock(&vnode->cb_lock);
250
David Howellsd2ddc772017-11-02 15:27:50 +0000251 if (call->cb_break == (vnode->cb_break + cbi->server->cb_s_break)) {
David Howellsc435ee32017-11-02 15:27:49 +0000252 vnode->cb_version = ntohl(*bp++);
253 cb_expiry = ntohl(*bp++);
254 vnode->cb_type = ntohl(*bp++);
255 vnode->cb_expires_at = cb_expiry + ktime_get_real_seconds();
David Howellsd2ddc772017-11-02 15:27:50 +0000256 old = vnode->cb_interest;
257 if (old != call->cbi) {
258 vnode->cb_interest = cbi;
259 cbi = old;
260 }
David Howellsc435ee32017-11-02 15:27:49 +0000261 set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
262 } else {
263 bp += 3;
264 }
265
266 write_sequnlock(&vnode->cb_lock);
David Howellsd2ddc772017-11-02 15:27:50 +0000267 call->cbi = cbi;
David Howells08e0e7c2007-04-26 15:55:03 -0700268 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700269}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
David Howells260a9802007-04-26 15:59:35 -0700271static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
272 struct afs_callback *cb)
273{
274 const __be32 *bp = *_bp;
275
276 cb->version = ntohl(*bp++);
277 cb->expiry = ntohl(*bp++);
278 cb->type = ntohl(*bp++);
279 *_bp = bp;
280}
281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282/*
David Howells08e0e7c2007-04-26 15:55:03 -0700283 * decode an AFSVolSync block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 */
David Howells08e0e7c2007-04-26 15:55:03 -0700285static void xdr_decode_AFSVolSync(const __be32 **_bp,
286 struct afs_volsync *volsync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
David Howells08e0e7c2007-04-26 15:55:03 -0700288 const __be32 *bp = *_bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
David Howells08e0e7c2007-04-26 15:55:03 -0700290 volsync->creation = ntohl(*bp++);
291 bp++; /* spare2 */
292 bp++; /* spare3 */
293 bp++; /* spare4 */
294 bp++; /* spare5 */
295 bp++; /* spare6 */
296 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700297}
David Howells08e0e7c2007-04-26 15:55:03 -0700298
299/*
David Howells31143d52007-05-09 02:33:46 -0700300 * encode the requested attributes into an AFSStoreStatus block
301 */
302static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
303{
304 __be32 *bp = *_bp;
305 u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
306
307 mask = 0;
308 if (attr->ia_valid & ATTR_MTIME) {
309 mask |= AFS_SET_MTIME;
310 mtime = attr->ia_mtime.tv_sec;
311 }
312
313 if (attr->ia_valid & ATTR_UID) {
314 mask |= AFS_SET_OWNER;
Eric W. Biedermana0a53862012-02-07 16:20:48 -0800315 owner = from_kuid(&init_user_ns, attr->ia_uid);
David Howells31143d52007-05-09 02:33:46 -0700316 }
317
318 if (attr->ia_valid & ATTR_GID) {
319 mask |= AFS_SET_GROUP;
Eric W. Biedermana0a53862012-02-07 16:20:48 -0800320 group = from_kgid(&init_user_ns, attr->ia_gid);
David Howells31143d52007-05-09 02:33:46 -0700321 }
322
323 if (attr->ia_valid & ATTR_MODE) {
324 mask |= AFS_SET_MODE;
325 mode = attr->ia_mode & S_IALLUGO;
326 }
327
328 *bp++ = htonl(mask);
329 *bp++ = htonl(mtime);
330 *bp++ = htonl(owner);
331 *bp++ = htonl(group);
332 *bp++ = htonl(mode);
333 *bp++ = 0; /* segment size */
334 *_bp = bp;
335}
336
337/*
David Howells45222b92007-05-10 22:22:20 -0700338 * decode an AFSFetchVolumeStatus block
339 */
340static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
341 struct afs_volume_status *vs)
342{
343 const __be32 *bp = *_bp;
344
345 vs->vid = ntohl(*bp++);
346 vs->parent_id = ntohl(*bp++);
347 vs->online = ntohl(*bp++);
348 vs->in_service = ntohl(*bp++);
349 vs->blessed = ntohl(*bp++);
350 vs->needs_salvage = ntohl(*bp++);
351 vs->type = ntohl(*bp++);
352 vs->min_quota = ntohl(*bp++);
353 vs->max_quota = ntohl(*bp++);
354 vs->blocks_in_use = ntohl(*bp++);
355 vs->part_blocks_avail = ntohl(*bp++);
356 vs->part_max_blocks = ntohl(*bp++);
357 *_bp = bp;
358}
359
360/*
David Howells08e0e7c2007-04-26 15:55:03 -0700361 * deliver reply data to an FS.FetchStatus
362 */
David Howells5cf9dd52018-04-09 21:12:31 +0100363static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
David Howells08e0e7c2007-04-26 15:55:03 -0700364{
David Howells97e30432017-11-02 15:27:48 +0000365 struct afs_vnode *vnode = call->reply[0];
David Howells08e0e7c2007-04-26 15:55:03 -0700366 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100367 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700368
David Howellsd0016482016-08-30 20:42:14 +0100369 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100370 if (ret < 0)
371 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700372
David Howellsc435ee32017-11-02 15:27:49 +0000373 _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
374
David Howells08e0e7c2007-04-26 15:55:03 -0700375 /* unmarshall the reply once we've received all of it */
376 bp = call->buffer;
David Howells5f702c82018-04-06 14:17:25 +0100377 if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
David Howellsdd9fbcb2018-04-06 14:17:24 +0100378 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100379 return afs_protocol_error(call, -EBADMSG);
David Howellsc435ee32017-11-02 15:27:49 +0000380 xdr_decode_AFSCallBack(call, vnode, &bp);
David Howells97e30432017-11-02 15:27:48 +0000381 if (call->reply[1])
382 xdr_decode_AFSVolSync(&bp, call->reply[1]);
David Howells08e0e7c2007-04-26 15:55:03 -0700383
384 _leave(" = 0 [done]");
385 return 0;
386}
387
388/*
389 * FS.FetchStatus operation type
390 */
David Howells5cf9dd52018-04-09 21:12:31 +0100391static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
392 .name = "FS.FetchStatus(vnode)",
David Howells025db802017-11-02 15:27:51 +0000393 .op = afs_FS_FetchStatus,
David Howells5cf9dd52018-04-09 21:12:31 +0100394 .deliver = afs_deliver_fs_fetch_status_vnode,
David Howells08e0e7c2007-04-26 15:55:03 -0700395 .destructor = afs_flat_call_destructor,
396};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398/*
399 * fetch the status information for a file
400 */
David Howells0c3a5ac2018-04-06 14:17:24 +0100401int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync,
402 bool new_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
David Howellsd2ddc772017-11-02 15:27:50 +0000404 struct afs_vnode *vnode = fc->vnode;
David Howells08e0e7c2007-04-26 15:55:03 -0700405 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000406 struct afs_net *net = afs_v2net(vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 __be32 *bp;
408
David Howells416351f2007-05-09 02:33:45 -0700409 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +0000410 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
David Howells5cf9dd52018-04-09 21:12:31 +0100412 call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode,
413 16, (21 + 3 + 6) * 4);
David Howellsd2ddc772017-11-02 15:27:50 +0000414 if (!call) {
415 fc->ac.error = -ENOMEM;
David Howells08e0e7c2007-04-26 15:55:03 -0700416 return -ENOMEM;
David Howellsd2ddc772017-11-02 15:27:50 +0000417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
David Howellsd2ddc772017-11-02 15:27:50 +0000419 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000420 call->reply[0] = vnode;
421 call->reply[1] = volsync;
David Howells0c3a5ac2018-04-06 14:17:24 +0100422 call->expected_version = new_inode ? 1 : vnode->status.data_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700425 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 bp[0] = htonl(FSFETCHSTATUS);
427 bp[1] = htonl(vnode->fid.vid);
428 bp[2] = htonl(vnode->fid.vnode);
429 bp[3] = htonl(vnode->fid.unique);
430
David Howellsd2ddc772017-11-02 15:27:50 +0000431 call->cb_break = fc->cb_break;
432 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000433 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000434 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsec268152007-04-26 15:49:28 -0700435}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437/*
David Howells08e0e7c2007-04-26 15:55:03 -0700438 * deliver reply data to an FS.FetchData
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 */
David Howellsd0016482016-08-30 20:42:14 +0100440static int afs_deliver_fs_fetch_data(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
David Howells97e30432017-11-02 15:27:48 +0000442 struct afs_vnode *vnode = call->reply[0];
443 struct afs_read *req = call->reply[2];
David Howells08e0e7c2007-04-26 15:55:03 -0700444 const __be32 *bp;
David Howells196ee9c2017-01-05 10:38:34 +0000445 unsigned int size;
David Howells08e0e7c2007-04-26 15:55:03 -0700446 void *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700448
David Howells6a0e3992017-03-16 16:27:46 +0000449 _enter("{%u,%zu/%u;%llu/%llu}",
David Howells196ee9c2017-01-05 10:38:34 +0000450 call->unmarshall, call->offset, call->count,
451 req->remain, req->actual_len);
David Howells08e0e7c2007-04-26 15:55:03 -0700452
453 switch (call->unmarshall) {
454 case 0:
David Howells196ee9c2017-01-05 10:38:34 +0000455 req->actual_len = 0;
David Howells08e0e7c2007-04-26 15:55:03 -0700456 call->offset = 0;
457 call->unmarshall++;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700458 if (call->operation_ID != FSFETCHDATA64) {
459 call->unmarshall++;
460 goto no_msw;
461 }
David Howells08e0e7c2007-04-26 15:55:03 -0700462
David Howellsb9b1f8d2007-05-10 03:15:21 -0700463 /* extract the upper part of the returned data length of an
464 * FSFETCHDATA64 op (which should always be 0 using this
465 * client) */
David Howells08e0e7c2007-04-26 15:55:03 -0700466 case 1:
David Howellsb9b1f8d2007-05-10 03:15:21 -0700467 _debug("extract data length (MSW)");
David Howellsd0016482016-08-30 20:42:14 +0100468 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +0100469 if (ret < 0)
470 return ret;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700471
David Howells196ee9c2017-01-05 10:38:34 +0000472 req->actual_len = ntohl(call->tmp);
473 req->actual_len <<= 32;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700474 call->offset = 0;
475 call->unmarshall++;
476
477 no_msw:
478 /* extract the returned data length */
479 case 2:
David Howells08e0e7c2007-04-26 15:55:03 -0700480 _debug("extract data length");
David Howellsd0016482016-08-30 20:42:14 +0100481 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +0100482 if (ret < 0)
483 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700484
David Howells196ee9c2017-01-05 10:38:34 +0000485 req->actual_len |= ntohl(call->tmp);
486 _debug("DATA length: %llu", req->actual_len);
David Howells196ee9c2017-01-05 10:38:34 +0000487
488 req->remain = req->actual_len;
489 call->offset = req->pos & (PAGE_SIZE - 1);
490 req->index = 0;
491 if (req->actual_len == 0)
492 goto no_more_data;
David Howells08e0e7c2007-04-26 15:55:03 -0700493 call->unmarshall++;
494
David Howells196ee9c2017-01-05 10:38:34 +0000495 begin_page:
David Howells6db3ac32017-03-16 16:27:44 +0000496 ASSERTCMP(req->index, <, req->nr_pages);
David Howells196ee9c2017-01-05 10:38:34 +0000497 if (req->remain > PAGE_SIZE - call->offset)
498 size = PAGE_SIZE - call->offset;
499 else
500 size = req->remain;
501 call->count = call->offset + size;
502 ASSERTCMP(call->count, <=, PAGE_SIZE);
503 req->remain -= size;
504
David Howells08e0e7c2007-04-26 15:55:03 -0700505 /* extract the returned data */
David Howellsb9b1f8d2007-05-10 03:15:21 -0700506 case 3:
David Howells6a0e3992017-03-16 16:27:46 +0000507 _debug("extract data %llu/%llu %zu/%u",
David Howells196ee9c2017-01-05 10:38:34 +0000508 req->remain, req->actual_len, call->offset, call->count);
509
510 buffer = kmap(req->pages[req->index]);
511 ret = afs_extract_data(call, buffer, call->count, true);
512 kunmap(req->pages[req->index]);
513 if (ret < 0)
514 return ret;
515 if (call->offset == PAGE_SIZE) {
516 if (req->page_done)
517 req->page_done(call, req);
David Howells29f06982017-03-16 16:27:46 +0000518 req->index++;
David Howells196ee9c2017-01-05 10:38:34 +0000519 if (req->remain > 0) {
David Howells196ee9c2017-01-05 10:38:34 +0000520 call->offset = 0;
David Howellse8e581a2017-03-16 16:27:44 +0000521 if (req->index >= req->nr_pages) {
522 call->unmarshall = 4;
David Howells6db3ac32017-03-16 16:27:44 +0000523 goto begin_discard;
David Howellse8e581a2017-03-16 16:27:44 +0000524 }
David Howells196ee9c2017-01-05 10:38:34 +0000525 goto begin_page;
526 }
David Howells08e0e7c2007-04-26 15:55:03 -0700527 }
David Howells6db3ac32017-03-16 16:27:44 +0000528 goto no_more_data;
529
530 /* Discard any excess data the server gave us */
531 begin_discard:
532 case 4:
David Howells6a0e3992017-03-16 16:27:46 +0000533 size = min_t(loff_t, sizeof(afs_discard_buffer), req->remain);
David Howells6db3ac32017-03-16 16:27:44 +0000534 call->count = size;
David Howells6a0e3992017-03-16 16:27:46 +0000535 _debug("extract discard %llu/%llu %zu/%u",
David Howells6db3ac32017-03-16 16:27:44 +0000536 req->remain, req->actual_len, call->offset, call->count);
537
538 call->offset = 0;
539 ret = afs_extract_data(call, afs_discard_buffer, call->count, true);
540 req->remain -= call->offset;
541 if (ret < 0)
542 return ret;
543 if (req->remain > 0)
544 goto begin_discard;
David Howells08e0e7c2007-04-26 15:55:03 -0700545
David Howells196ee9c2017-01-05 10:38:34 +0000546 no_more_data:
David Howells08e0e7c2007-04-26 15:55:03 -0700547 call->offset = 0;
David Howells6db3ac32017-03-16 16:27:44 +0000548 call->unmarshall = 5;
David Howells08e0e7c2007-04-26 15:55:03 -0700549
550 /* extract the metadata */
David Howells6db3ac32017-03-16 16:27:44 +0000551 case 5:
David Howellsd0016482016-08-30 20:42:14 +0100552 ret = afs_extract_data(call, call->buffer,
553 (21 + 3 + 6) * 4, false);
David Howells372ee162016-08-03 14:11:40 +0100554 if (ret < 0)
555 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700556
557 bp = call->buffer;
David Howells5f702c82018-04-06 14:17:25 +0100558 if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
David Howellsf3ddee82018-04-06 14:17:25 +0100559 &vnode->status.data_version, req) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100560 return afs_protocol_error(call, -EBADMSG);
David Howellsc435ee32017-11-02 15:27:49 +0000561 xdr_decode_AFSCallBack(call, vnode, &bp);
David Howells97e30432017-11-02 15:27:48 +0000562 if (call->reply[1])
563 xdr_decode_AFSVolSync(&bp, call->reply[1]);
David Howells08e0e7c2007-04-26 15:55:03 -0700564
565 call->offset = 0;
566 call->unmarshall++;
567
David Howells6db3ac32017-03-16 16:27:44 +0000568 case 6:
David Howells08e0e7c2007-04-26 15:55:03 -0700569 break;
570 }
571
David Howells6db3ac32017-03-16 16:27:44 +0000572 for (; req->index < req->nr_pages; req->index++) {
573 if (call->count < PAGE_SIZE)
574 zero_user_segment(req->pages[req->index],
575 call->count, PAGE_SIZE);
David Howells196ee9c2017-01-05 10:38:34 +0000576 if (req->page_done)
577 req->page_done(call, req);
David Howells6db3ac32017-03-16 16:27:44 +0000578 call->count = 0;
David Howells416351f2007-05-09 02:33:45 -0700579 }
580
David Howells08e0e7c2007-04-26 15:55:03 -0700581 _leave(" = 0 [done]");
582 return 0;
583}
584
David Howells196ee9c2017-01-05 10:38:34 +0000585static void afs_fetch_data_destructor(struct afs_call *call)
586{
David Howells97e30432017-11-02 15:27:48 +0000587 struct afs_read *req = call->reply[2];
David Howells196ee9c2017-01-05 10:38:34 +0000588
589 afs_put_read(req);
590 afs_flat_call_destructor(call);
591}
592
David Howells08e0e7c2007-04-26 15:55:03 -0700593/*
594 * FS.FetchData operation type
595 */
596static const struct afs_call_type afs_RXFSFetchData = {
David Howells00d3b7a2007-04-26 15:57:07 -0700597 .name = "FS.FetchData",
David Howells025db802017-11-02 15:27:51 +0000598 .op = afs_FS_FetchData,
David Howells08e0e7c2007-04-26 15:55:03 -0700599 .deliver = afs_deliver_fs_fetch_data,
David Howells196ee9c2017-01-05 10:38:34 +0000600 .destructor = afs_fetch_data_destructor,
David Howells08e0e7c2007-04-26 15:55:03 -0700601};
602
David Howellsb9b1f8d2007-05-10 03:15:21 -0700603static const struct afs_call_type afs_RXFSFetchData64 = {
604 .name = "FS.FetchData64",
David Howells025db802017-11-02 15:27:51 +0000605 .op = afs_FS_FetchData64,
David Howellsb9b1f8d2007-05-10 03:15:21 -0700606 .deliver = afs_deliver_fs_fetch_data,
David Howells196ee9c2017-01-05 10:38:34 +0000607 .destructor = afs_fetch_data_destructor,
David Howellsb9b1f8d2007-05-10 03:15:21 -0700608};
609
610/*
611 * fetch data from a very large file
612 */
David Howellsd2ddc772017-11-02 15:27:50 +0000613static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
David Howellsb9b1f8d2007-05-10 03:15:21 -0700614{
David Howellsd2ddc772017-11-02 15:27:50 +0000615 struct afs_vnode *vnode = fc->vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700616 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000617 struct afs_net *net = afs_v2net(vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700618 __be32 *bp;
619
620 _enter("");
621
David Howellsf044c882017-11-02 15:27:45 +0000622 call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700623 if (!call)
624 return -ENOMEM;
625
David Howellsd2ddc772017-11-02 15:27:50 +0000626 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000627 call->reply[0] = vnode;
628 call->reply[1] = NULL; /* volsync */
629 call->reply[2] = req;
David Howells0c3a5ac2018-04-06 14:17:24 +0100630 call->expected_version = vnode->status.data_version;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700631
632 /* marshall the parameters */
633 bp = call->request;
634 bp[0] = htonl(FSFETCHDATA64);
635 bp[1] = htonl(vnode->fid.vid);
636 bp[2] = htonl(vnode->fid.vnode);
637 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000638 bp[4] = htonl(upper_32_bits(req->pos));
639 bp[5] = htonl(lower_32_bits(req->pos));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700640 bp[6] = 0;
David Howells196ee9c2017-01-05 10:38:34 +0000641 bp[7] = htonl(lower_32_bits(req->len));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700642
David Howellsf3ddee82018-04-06 14:17:25 +0100643 refcount_inc(&req->usage);
David Howellsd2ddc772017-11-02 15:27:50 +0000644 call->cb_break = fc->cb_break;
645 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000646 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000647 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700648}
649
David Howells08e0e7c2007-04-26 15:55:03 -0700650/*
651 * fetch data from a file
652 */
David Howellsd2ddc772017-11-02 15:27:50 +0000653int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
David Howells08e0e7c2007-04-26 15:55:03 -0700654{
David Howellsd2ddc772017-11-02 15:27:50 +0000655 struct afs_vnode *vnode = fc->vnode;
David Howells08e0e7c2007-04-26 15:55:03 -0700656 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000657 struct afs_net *net = afs_v2net(vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 __be32 *bp;
659
David Howells196ee9c2017-01-05 10:38:34 +0000660 if (upper_32_bits(req->pos) ||
661 upper_32_bits(req->len) ||
662 upper_32_bits(req->pos + req->len))
David Howellsd2ddc772017-11-02 15:27:50 +0000663 return afs_fs_fetch_data64(fc, req);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700664
David Howells08e0e7c2007-04-26 15:55:03 -0700665 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
David Howellsf044c882017-11-02 15:27:45 +0000667 call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700668 if (!call)
669 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
David Howellsd2ddc772017-11-02 15:27:50 +0000671 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000672 call->reply[0] = vnode;
673 call->reply[1] = NULL; /* volsync */
674 call->reply[2] = req;
David Howells0c3a5ac2018-04-06 14:17:24 +0100675 call->expected_version = vnode->status.data_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
677 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700678 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 bp[0] = htonl(FSFETCHDATA);
David Howells08e0e7c2007-04-26 15:55:03 -0700680 bp[1] = htonl(vnode->fid.vid);
681 bp[2] = htonl(vnode->fid.vnode);
682 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000683 bp[4] = htonl(lower_32_bits(req->pos));
684 bp[5] = htonl(lower_32_bits(req->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
David Howellsf3ddee82018-04-06 14:17:25 +0100686 refcount_inc(&req->usage);
David Howellsd2ddc772017-11-02 15:27:50 +0000687 call->cb_break = fc->cb_break;
688 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000689 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000690 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsec268152007-04-26 15:49:28 -0700691}
David Howells260a9802007-04-26 15:59:35 -0700692
693/*
694 * deliver reply data to an FS.CreateFile or an FS.MakeDir
695 */
David Howellsd0016482016-08-30 20:42:14 +0100696static int afs_deliver_fs_create_vnode(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700697{
David Howells97e30432017-11-02 15:27:48 +0000698 struct afs_vnode *vnode = call->reply[0];
David Howells260a9802007-04-26 15:59:35 -0700699 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100700 int ret;
David Howells260a9802007-04-26 15:59:35 -0700701
David Howellsd0016482016-08-30 20:42:14 +0100702 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700703
David Howellsd0016482016-08-30 20:42:14 +0100704 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100705 if (ret < 0)
706 return ret;
David Howells260a9802007-04-26 15:59:35 -0700707
708 /* unmarshall the reply once we've received all of it */
709 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +0000710 xdr_decode_AFSFid(&bp, call->reply[1]);
David Howells5f702c82018-04-06 14:17:25 +0100711 if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 ||
712 xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
David Howellsdd9fbcb2018-04-06 14:17:24 +0100713 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100714 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +0000715 xdr_decode_AFSCallBack_raw(&bp, call->reply[3]);
716 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700717
718 _leave(" = 0 [done]");
719 return 0;
720}
721
722/*
723 * FS.CreateFile and FS.MakeDir operation type
724 */
David Howells025db802017-11-02 15:27:51 +0000725static const struct afs_call_type afs_RXFSCreateFile = {
726 .name = "FS.CreateFile",
727 .op = afs_FS_CreateFile,
728 .deliver = afs_deliver_fs_create_vnode,
729 .destructor = afs_flat_call_destructor,
730};
731
732static const struct afs_call_type afs_RXFSMakeDir = {
733 .name = "FS.MakeDir",
734 .op = afs_FS_MakeDir,
David Howells260a9802007-04-26 15:59:35 -0700735 .deliver = afs_deliver_fs_create_vnode,
David Howells260a9802007-04-26 15:59:35 -0700736 .destructor = afs_flat_call_destructor,
737};
738
739/*
740 * create a file or make a directory
741 */
David Howells8b2a4642017-11-02 15:27:50 +0000742int afs_fs_create(struct afs_fs_cursor *fc,
David Howells260a9802007-04-26 15:59:35 -0700743 const char *name,
744 umode_t mode,
David Howells63a46812018-04-06 14:17:25 +0100745 u64 current_data_version,
David Howells260a9802007-04-26 15:59:35 -0700746 struct afs_fid *newfid,
747 struct afs_file_status *newstatus,
David Howellsd2ddc772017-11-02 15:27:50 +0000748 struct afs_callback *newcb)
David Howells260a9802007-04-26 15:59:35 -0700749{
David Howellsd2ddc772017-11-02 15:27:50 +0000750 struct afs_vnode *vnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700751 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000752 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700753 size_t namesz, reqsz, padsz;
754 __be32 *bp;
755
756 _enter("");
757
758 namesz = strlen(name);
759 padsz = (4 - (namesz & 3)) & 3;
760 reqsz = (5 * 4) + namesz + padsz + (6 * 4);
761
David Howells025db802017-11-02 15:27:51 +0000762 call = afs_alloc_flat_call(
763 net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile,
764 reqsz, (3 + 21 + 21 + 3 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -0700765 if (!call)
766 return -ENOMEM;
767
David Howellsd2ddc772017-11-02 15:27:50 +0000768 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000769 call->reply[0] = vnode;
770 call->reply[1] = newfid;
771 call->reply[2] = newstatus;
772 call->reply[3] = newcb;
David Howells63a46812018-04-06 14:17:25 +0100773 call->expected_version = current_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -0700774
775 /* marshall the parameters */
776 bp = call->request;
777 *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
778 *bp++ = htonl(vnode->fid.vid);
779 *bp++ = htonl(vnode->fid.vnode);
780 *bp++ = htonl(vnode->fid.unique);
781 *bp++ = htonl(namesz);
782 memcpy(bp, name, namesz);
783 bp = (void *) bp + namesz;
784 if (padsz > 0) {
785 memset(bp, 0, padsz);
786 bp = (void *) bp + padsz;
787 }
Marc Dionneab94f5d2017-03-16 16:27:47 +0000788 *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
789 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howells260a9802007-04-26 15:59:35 -0700790 *bp++ = 0; /* owner */
791 *bp++ = 0; /* group */
792 *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
793 *bp++ = 0; /* segment size */
794
David Howellsd2ddc772017-11-02 15:27:50 +0000795 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000796 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000797 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700798}
799
800/*
801 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
802 */
David Howellsd0016482016-08-30 20:42:14 +0100803static int afs_deliver_fs_remove(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700804{
David Howells97e30432017-11-02 15:27:48 +0000805 struct afs_vnode *vnode = call->reply[0];
David Howells260a9802007-04-26 15:59:35 -0700806 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100807 int ret;
David Howells260a9802007-04-26 15:59:35 -0700808
David Howellsd0016482016-08-30 20:42:14 +0100809 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700810
David Howellsd0016482016-08-30 20:42:14 +0100811 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100812 if (ret < 0)
813 return ret;
David Howells260a9802007-04-26 15:59:35 -0700814
815 /* unmarshall the reply once we've received all of it */
816 bp = call->buffer;
David Howells5f702c82018-04-06 14:17:25 +0100817 if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
David Howellsdd9fbcb2018-04-06 14:17:24 +0100818 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100819 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +0000820 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700821
822 _leave(" = 0 [done]");
823 return 0;
824}
825
826/*
827 * FS.RemoveDir/FS.RemoveFile operation type
828 */
David Howells025db802017-11-02 15:27:51 +0000829static const struct afs_call_type afs_RXFSRemoveFile = {
830 .name = "FS.RemoveFile",
831 .op = afs_FS_RemoveFile,
832 .deliver = afs_deliver_fs_remove,
833 .destructor = afs_flat_call_destructor,
834};
835
836static const struct afs_call_type afs_RXFSRemoveDir = {
837 .name = "FS.RemoveDir",
838 .op = afs_FS_RemoveDir,
David Howells260a9802007-04-26 15:59:35 -0700839 .deliver = afs_deliver_fs_remove,
David Howells260a9802007-04-26 15:59:35 -0700840 .destructor = afs_flat_call_destructor,
841};
842
843/*
844 * remove a file or directory
845 */
David Howells63a46812018-04-06 14:17:25 +0100846int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir,
847 u64 current_data_version)
David Howells260a9802007-04-26 15:59:35 -0700848{
David Howellsd2ddc772017-11-02 15:27:50 +0000849 struct afs_vnode *vnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700850 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000851 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700852 size_t namesz, reqsz, padsz;
853 __be32 *bp;
854
855 _enter("");
856
857 namesz = strlen(name);
858 padsz = (4 - (namesz & 3)) & 3;
859 reqsz = (5 * 4) + namesz + padsz;
860
David Howells025db802017-11-02 15:27:51 +0000861 call = afs_alloc_flat_call(
862 net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile,
863 reqsz, (21 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -0700864 if (!call)
865 return -ENOMEM;
866
David Howellsd2ddc772017-11-02 15:27:50 +0000867 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000868 call->reply[0] = vnode;
David Howells63a46812018-04-06 14:17:25 +0100869 call->expected_version = current_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -0700870
871 /* marshall the parameters */
872 bp = call->request;
873 *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
874 *bp++ = htonl(vnode->fid.vid);
875 *bp++ = htonl(vnode->fid.vnode);
876 *bp++ = htonl(vnode->fid.unique);
877 *bp++ = htonl(namesz);
878 memcpy(bp, name, namesz);
879 bp = (void *) bp + namesz;
880 if (padsz > 0) {
881 memset(bp, 0, padsz);
882 bp = (void *) bp + padsz;
883 }
884
David Howellsd2ddc772017-11-02 15:27:50 +0000885 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000886 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000887 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700888}
889
890/*
891 * deliver reply data to an FS.Link
892 */
David Howellsd0016482016-08-30 20:42:14 +0100893static int afs_deliver_fs_link(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700894{
David Howells97e30432017-11-02 15:27:48 +0000895 struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1];
David Howells260a9802007-04-26 15:59:35 -0700896 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100897 int ret;
David Howells260a9802007-04-26 15:59:35 -0700898
David Howellsd0016482016-08-30 20:42:14 +0100899 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700900
David Howellsd0016482016-08-30 20:42:14 +0100901 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100902 if (ret < 0)
903 return ret;
David Howells260a9802007-04-26 15:59:35 -0700904
905 /* unmarshall the reply once we've received all of it */
906 bp = call->buffer;
David Howells5f702c82018-04-06 14:17:25 +0100907 if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 ||
908 xdr_decode_AFSFetchStatus(call, &bp, &dvnode->status, dvnode,
David Howellsdd9fbcb2018-04-06 14:17:24 +0100909 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100910 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +0000911 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700912
913 _leave(" = 0 [done]");
914 return 0;
915}
916
917/*
918 * FS.Link operation type
919 */
920static const struct afs_call_type afs_RXFSLink = {
921 .name = "FS.Link",
David Howells025db802017-11-02 15:27:51 +0000922 .op = afs_FS_Link,
David Howells260a9802007-04-26 15:59:35 -0700923 .deliver = afs_deliver_fs_link,
David Howells260a9802007-04-26 15:59:35 -0700924 .destructor = afs_flat_call_destructor,
925};
926
927/*
928 * make a hard link
929 */
David Howellsd2ddc772017-11-02 15:27:50 +0000930int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
David Howells63a46812018-04-06 14:17:25 +0100931 const char *name, u64 current_data_version)
David Howells260a9802007-04-26 15:59:35 -0700932{
David Howellsd2ddc772017-11-02 15:27:50 +0000933 struct afs_vnode *dvnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700934 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000935 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700936 size_t namesz, reqsz, padsz;
937 __be32 *bp;
938
939 _enter("");
940
941 namesz = strlen(name);
942 padsz = (4 - (namesz & 3)) & 3;
943 reqsz = (5 * 4) + namesz + padsz + (3 * 4);
944
David Howellsf044c882017-11-02 15:27:45 +0000945 call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -0700946 if (!call)
947 return -ENOMEM;
948
David Howellsd2ddc772017-11-02 15:27:50 +0000949 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000950 call->reply[0] = dvnode;
951 call->reply[1] = vnode;
David Howells63a46812018-04-06 14:17:25 +0100952 call->expected_version = current_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -0700953
954 /* marshall the parameters */
955 bp = call->request;
956 *bp++ = htonl(FSLINK);
957 *bp++ = htonl(dvnode->fid.vid);
958 *bp++ = htonl(dvnode->fid.vnode);
959 *bp++ = htonl(dvnode->fid.unique);
960 *bp++ = htonl(namesz);
961 memcpy(bp, name, namesz);
962 bp = (void *) bp + namesz;
963 if (padsz > 0) {
964 memset(bp, 0, padsz);
965 bp = (void *) bp + padsz;
966 }
967 *bp++ = htonl(vnode->fid.vid);
968 *bp++ = htonl(vnode->fid.vnode);
969 *bp++ = htonl(vnode->fid.unique);
970
David Howellsd2ddc772017-11-02 15:27:50 +0000971 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000972 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000973 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700974}
975
976/*
977 * deliver reply data to an FS.Symlink
978 */
David Howellsd0016482016-08-30 20:42:14 +0100979static int afs_deliver_fs_symlink(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700980{
David Howells97e30432017-11-02 15:27:48 +0000981 struct afs_vnode *vnode = call->reply[0];
David Howells260a9802007-04-26 15:59:35 -0700982 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100983 int ret;
David Howells260a9802007-04-26 15:59:35 -0700984
David Howellsd0016482016-08-30 20:42:14 +0100985 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700986
David Howellsd0016482016-08-30 20:42:14 +0100987 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100988 if (ret < 0)
989 return ret;
David Howells260a9802007-04-26 15:59:35 -0700990
991 /* unmarshall the reply once we've received all of it */
992 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +0000993 xdr_decode_AFSFid(&bp, call->reply[1]);
David Howells5f702c82018-04-06 14:17:25 +0100994 if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) ||
995 xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
David Howellsdd9fbcb2018-04-06 14:17:24 +0100996 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100997 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +0000998 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700999
1000 _leave(" = 0 [done]");
1001 return 0;
1002}
1003
1004/*
1005 * FS.Symlink operation type
1006 */
1007static const struct afs_call_type afs_RXFSSymlink = {
1008 .name = "FS.Symlink",
David Howells025db802017-11-02 15:27:51 +00001009 .op = afs_FS_Symlink,
David Howells260a9802007-04-26 15:59:35 -07001010 .deliver = afs_deliver_fs_symlink,
David Howells260a9802007-04-26 15:59:35 -07001011 .destructor = afs_flat_call_destructor,
1012};
1013
1014/*
1015 * create a symbolic link
1016 */
David Howells8b2a4642017-11-02 15:27:50 +00001017int afs_fs_symlink(struct afs_fs_cursor *fc,
David Howells260a9802007-04-26 15:59:35 -07001018 const char *name,
1019 const char *contents,
David Howells63a46812018-04-06 14:17:25 +01001020 u64 current_data_version,
David Howells260a9802007-04-26 15:59:35 -07001021 struct afs_fid *newfid,
David Howellsd2ddc772017-11-02 15:27:50 +00001022 struct afs_file_status *newstatus)
David Howells260a9802007-04-26 15:59:35 -07001023{
David Howellsd2ddc772017-11-02 15:27:50 +00001024 struct afs_vnode *vnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -07001025 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001026 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -07001027 size_t namesz, reqsz, padsz, c_namesz, c_padsz;
1028 __be32 *bp;
1029
1030 _enter("");
1031
1032 namesz = strlen(name);
1033 padsz = (4 - (namesz & 3)) & 3;
1034
1035 c_namesz = strlen(contents);
1036 c_padsz = (4 - (c_namesz & 3)) & 3;
1037
1038 reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
1039
David Howellsf044c882017-11-02 15:27:45 +00001040 call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
David Howells260a9802007-04-26 15:59:35 -07001041 (3 + 21 + 21 + 6) * 4);
1042 if (!call)
1043 return -ENOMEM;
1044
David Howellsd2ddc772017-11-02 15:27:50 +00001045 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001046 call->reply[0] = vnode;
1047 call->reply[1] = newfid;
1048 call->reply[2] = newstatus;
David Howells63a46812018-04-06 14:17:25 +01001049 call->expected_version = current_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -07001050
1051 /* marshall the parameters */
1052 bp = call->request;
1053 *bp++ = htonl(FSSYMLINK);
1054 *bp++ = htonl(vnode->fid.vid);
1055 *bp++ = htonl(vnode->fid.vnode);
1056 *bp++ = htonl(vnode->fid.unique);
1057 *bp++ = htonl(namesz);
1058 memcpy(bp, name, namesz);
1059 bp = (void *) bp + namesz;
1060 if (padsz > 0) {
1061 memset(bp, 0, padsz);
1062 bp = (void *) bp + padsz;
1063 }
1064 *bp++ = htonl(c_namesz);
1065 memcpy(bp, contents, c_namesz);
1066 bp = (void *) bp + c_namesz;
1067 if (c_padsz > 0) {
1068 memset(bp, 0, c_padsz);
1069 bp = (void *) bp + c_padsz;
1070 }
Marc Dionneab94f5d2017-03-16 16:27:47 +00001071 *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
1072 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howells260a9802007-04-26 15:59:35 -07001073 *bp++ = 0; /* owner */
1074 *bp++ = 0; /* group */
1075 *bp++ = htonl(S_IRWXUGO); /* unix mode */
1076 *bp++ = 0; /* segment size */
1077
David Howellsd2ddc772017-11-02 15:27:50 +00001078 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001079 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001080 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -07001081}
1082
1083/*
1084 * deliver reply data to an FS.Rename
1085 */
David Howellsd0016482016-08-30 20:42:14 +01001086static int afs_deliver_fs_rename(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -07001087{
David Howells97e30432017-11-02 15:27:48 +00001088 struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1];
David Howells260a9802007-04-26 15:59:35 -07001089 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001090 int ret;
David Howells260a9802007-04-26 15:59:35 -07001091
David Howellsd0016482016-08-30 20:42:14 +01001092 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -07001093
David Howellsd0016482016-08-30 20:42:14 +01001094 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001095 if (ret < 0)
1096 return ret;
David Howells260a9802007-04-26 15:59:35 -07001097
1098 /* unmarshall the reply once we've received all of it */
1099 bp = call->buffer;
David Howells5f702c82018-04-06 14:17:25 +01001100 if (xdr_decode_AFSFetchStatus(call, &bp, &orig_dvnode->status, orig_dvnode,
David Howellsdd9fbcb2018-04-06 14:17:24 +01001101 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01001102 return afs_protocol_error(call, -EBADMSG);
David Howellsdd9fbcb2018-04-06 14:17:24 +01001103 if (new_dvnode != orig_dvnode &&
David Howells5f702c82018-04-06 14:17:25 +01001104 xdr_decode_AFSFetchStatus(call, &bp, &new_dvnode->status, new_dvnode,
David Howellsdd9fbcb2018-04-06 14:17:24 +01001105 &call->expected_version_2, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01001106 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +00001107 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -07001108
1109 _leave(" = 0 [done]");
1110 return 0;
1111}
1112
1113/*
1114 * FS.Rename operation type
1115 */
1116static const struct afs_call_type afs_RXFSRename = {
1117 .name = "FS.Rename",
David Howells025db802017-11-02 15:27:51 +00001118 .op = afs_FS_Rename,
David Howells260a9802007-04-26 15:59:35 -07001119 .deliver = afs_deliver_fs_rename,
David Howells260a9802007-04-26 15:59:35 -07001120 .destructor = afs_flat_call_destructor,
1121};
1122
1123/*
1124 * create a symbolic link
1125 */
David Howells8b2a4642017-11-02 15:27:50 +00001126int afs_fs_rename(struct afs_fs_cursor *fc,
David Howells260a9802007-04-26 15:59:35 -07001127 const char *orig_name,
1128 struct afs_vnode *new_dvnode,
David Howells63a46812018-04-06 14:17:25 +01001129 const char *new_name,
1130 u64 current_orig_data_version,
1131 u64 current_new_data_version)
David Howells260a9802007-04-26 15:59:35 -07001132{
David Howellsd2ddc772017-11-02 15:27:50 +00001133 struct afs_vnode *orig_dvnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -07001134 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001135 struct afs_net *net = afs_v2net(orig_dvnode);
David Howells260a9802007-04-26 15:59:35 -07001136 size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1137 __be32 *bp;
1138
1139 _enter("");
1140
1141 o_namesz = strlen(orig_name);
1142 o_padsz = (4 - (o_namesz & 3)) & 3;
1143
1144 n_namesz = strlen(new_name);
1145 n_padsz = (4 - (n_namesz & 3)) & 3;
1146
1147 reqsz = (4 * 4) +
1148 4 + o_namesz + o_padsz +
1149 (3 * 4) +
1150 4 + n_namesz + n_padsz;
1151
David Howellsf044c882017-11-02 15:27:45 +00001152 call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -07001153 if (!call)
1154 return -ENOMEM;
1155
David Howellsd2ddc772017-11-02 15:27:50 +00001156 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001157 call->reply[0] = orig_dvnode;
1158 call->reply[1] = new_dvnode;
David Howells63a46812018-04-06 14:17:25 +01001159 call->expected_version = current_orig_data_version + 1;
1160 call->expected_version_2 = current_new_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -07001161
1162 /* marshall the parameters */
1163 bp = call->request;
1164 *bp++ = htonl(FSRENAME);
1165 *bp++ = htonl(orig_dvnode->fid.vid);
1166 *bp++ = htonl(orig_dvnode->fid.vnode);
1167 *bp++ = htonl(orig_dvnode->fid.unique);
1168 *bp++ = htonl(o_namesz);
1169 memcpy(bp, orig_name, o_namesz);
1170 bp = (void *) bp + o_namesz;
1171 if (o_padsz > 0) {
1172 memset(bp, 0, o_padsz);
1173 bp = (void *) bp + o_padsz;
1174 }
1175
1176 *bp++ = htonl(new_dvnode->fid.vid);
1177 *bp++ = htonl(new_dvnode->fid.vnode);
1178 *bp++ = htonl(new_dvnode->fid.unique);
1179 *bp++ = htonl(n_namesz);
1180 memcpy(bp, new_name, n_namesz);
1181 bp = (void *) bp + n_namesz;
1182 if (n_padsz > 0) {
1183 memset(bp, 0, n_padsz);
1184 bp = (void *) bp + n_padsz;
1185 }
1186
David Howellsd2ddc772017-11-02 15:27:50 +00001187 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001188 trace_afs_make_fs_call(call, &orig_dvnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001189 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -07001190}
David Howells31143d52007-05-09 02:33:46 -07001191
1192/*
1193 * deliver reply data to an FS.StoreData
1194 */
David Howellsd0016482016-08-30 20:42:14 +01001195static int afs_deliver_fs_store_data(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001196{
David Howells97e30432017-11-02 15:27:48 +00001197 struct afs_vnode *vnode = call->reply[0];
David Howells31143d52007-05-09 02:33:46 -07001198 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001199 int ret;
David Howells31143d52007-05-09 02:33:46 -07001200
David Howellsd0016482016-08-30 20:42:14 +01001201 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001202
David Howellsd0016482016-08-30 20:42:14 +01001203 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001204 if (ret < 0)
1205 return ret;
David Howells31143d52007-05-09 02:33:46 -07001206
1207 /* unmarshall the reply once we've received all of it */
1208 bp = call->buffer;
David Howells5f702c82018-04-06 14:17:25 +01001209 if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
David Howellsdd9fbcb2018-04-06 14:17:24 +01001210 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01001211 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +00001212 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells31143d52007-05-09 02:33:46 -07001213
1214 afs_pages_written_back(vnode, call);
1215
1216 _leave(" = 0 [done]");
1217 return 0;
1218}
1219
1220/*
1221 * FS.StoreData operation type
1222 */
1223static const struct afs_call_type afs_RXFSStoreData = {
1224 .name = "FS.StoreData",
David Howells025db802017-11-02 15:27:51 +00001225 .op = afs_FS_StoreData,
David Howells31143d52007-05-09 02:33:46 -07001226 .deliver = afs_deliver_fs_store_data,
David Howells31143d52007-05-09 02:33:46 -07001227 .destructor = afs_flat_call_destructor,
1228};
1229
David Howellsb9b1f8d2007-05-10 03:15:21 -07001230static const struct afs_call_type afs_RXFSStoreData64 = {
1231 .name = "FS.StoreData64",
David Howells025db802017-11-02 15:27:51 +00001232 .op = afs_FS_StoreData64,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001233 .deliver = afs_deliver_fs_store_data,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001234 .destructor = afs_flat_call_destructor,
1235};
1236
1237/*
1238 * store a set of pages to a very large file
1239 */
David Howells8b2a4642017-11-02 15:27:50 +00001240static int afs_fs_store_data64(struct afs_fs_cursor *fc,
David Howells4343d002017-11-02 15:27:52 +00001241 struct address_space *mapping,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001242 pgoff_t first, pgoff_t last,
1243 unsigned offset, unsigned to,
David Howellsd2ddc772017-11-02 15:27:50 +00001244 loff_t size, loff_t pos, loff_t i_size)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001245{
David Howells4343d002017-11-02 15:27:52 +00001246 struct afs_vnode *vnode = fc->vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001247 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001248 struct afs_net *net = afs_v2net(vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001249 __be32 *bp;
1250
1251 _enter(",%x,{%x:%u},,",
David Howells4343d002017-11-02 15:27:52 +00001252 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001253
David Howellsf044c882017-11-02 15:27:45 +00001254 call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001255 (4 + 6 + 3 * 2) * 4,
1256 (21 + 6) * 4);
1257 if (!call)
1258 return -ENOMEM;
1259
David Howells4343d002017-11-02 15:27:52 +00001260 call->key = fc->key;
1261 call->mapping = mapping;
David Howells97e30432017-11-02 15:27:48 +00001262 call->reply[0] = vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001263 call->first = first;
1264 call->last = last;
1265 call->first_offset = offset;
1266 call->last_to = to;
1267 call->send_pages = true;
David Howells0c3a5ac2018-04-06 14:17:24 +01001268 call->expected_version = vnode->status.data_version + 1;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001269
1270 /* marshall the parameters */
1271 bp = call->request;
1272 *bp++ = htonl(FSSTOREDATA64);
1273 *bp++ = htonl(vnode->fid.vid);
1274 *bp++ = htonl(vnode->fid.vnode);
1275 *bp++ = htonl(vnode->fid.unique);
1276
Marc Dionneab94f5d2017-03-16 16:27:47 +00001277 *bp++ = htonl(AFS_SET_MTIME); /* mask */
1278 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howellsb9b1f8d2007-05-10 03:15:21 -07001279 *bp++ = 0; /* owner */
1280 *bp++ = 0; /* group */
1281 *bp++ = 0; /* unix mode */
1282 *bp++ = 0; /* segment size */
1283
1284 *bp++ = htonl(pos >> 32);
1285 *bp++ = htonl((u32) pos);
1286 *bp++ = htonl(size >> 32);
1287 *bp++ = htonl((u32) size);
1288 *bp++ = htonl(i_size >> 32);
1289 *bp++ = htonl((u32) i_size);
1290
David Howells025db802017-11-02 15:27:51 +00001291 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001292 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001293}
1294
David Howells31143d52007-05-09 02:33:46 -07001295/*
1296 * store a set of pages
1297 */
David Howells4343d002017-11-02 15:27:52 +00001298int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
David Howells31143d52007-05-09 02:33:46 -07001299 pgoff_t first, pgoff_t last,
David Howellsd2ddc772017-11-02 15:27:50 +00001300 unsigned offset, unsigned to)
David Howells31143d52007-05-09 02:33:46 -07001301{
David Howells4343d002017-11-02 15:27:52 +00001302 struct afs_vnode *vnode = fc->vnode;
David Howells31143d52007-05-09 02:33:46 -07001303 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001304 struct afs_net *net = afs_v2net(vnode);
David Howells31143d52007-05-09 02:33:46 -07001305 loff_t size, pos, i_size;
1306 __be32 *bp;
1307
1308 _enter(",%x,{%x:%u},,",
David Howells4343d002017-11-02 15:27:52 +00001309 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howells31143d52007-05-09 02:33:46 -07001310
David Howells146a1192017-03-16 16:27:47 +00001311 size = (loff_t)to - (loff_t)offset;
David Howells31143d52007-05-09 02:33:46 -07001312 if (first != last)
1313 size += (loff_t)(last - first) << PAGE_SHIFT;
1314 pos = (loff_t)first << PAGE_SHIFT;
1315 pos += offset;
1316
1317 i_size = i_size_read(&vnode->vfs_inode);
1318 if (pos + size > i_size)
1319 i_size = size + pos;
1320
1321 _debug("size %llx, at %llx, i_size %llx",
1322 (unsigned long long) size, (unsigned long long) pos,
1323 (unsigned long long) i_size);
1324
David Howellsb9b1f8d2007-05-10 03:15:21 -07001325 if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
David Howells4343d002017-11-02 15:27:52 +00001326 return afs_fs_store_data64(fc, mapping, first, last, offset, to,
David Howellsd2ddc772017-11-02 15:27:50 +00001327 size, pos, i_size);
David Howells31143d52007-05-09 02:33:46 -07001328
David Howellsf044c882017-11-02 15:27:45 +00001329 call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
David Howells31143d52007-05-09 02:33:46 -07001330 (4 + 6 + 3) * 4,
1331 (21 + 6) * 4);
1332 if (!call)
1333 return -ENOMEM;
1334
David Howells4343d002017-11-02 15:27:52 +00001335 call->key = fc->key;
1336 call->mapping = mapping;
David Howells97e30432017-11-02 15:27:48 +00001337 call->reply[0] = vnode;
David Howells31143d52007-05-09 02:33:46 -07001338 call->first = first;
1339 call->last = last;
1340 call->first_offset = offset;
1341 call->last_to = to;
1342 call->send_pages = true;
David Howells0c3a5ac2018-04-06 14:17:24 +01001343 call->expected_version = vnode->status.data_version + 1;
David Howells31143d52007-05-09 02:33:46 -07001344
1345 /* marshall the parameters */
1346 bp = call->request;
1347 *bp++ = htonl(FSSTOREDATA);
1348 *bp++ = htonl(vnode->fid.vid);
1349 *bp++ = htonl(vnode->fid.vnode);
1350 *bp++ = htonl(vnode->fid.unique);
1351
Marc Dionneab94f5d2017-03-16 16:27:47 +00001352 *bp++ = htonl(AFS_SET_MTIME); /* mask */
1353 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howells31143d52007-05-09 02:33:46 -07001354 *bp++ = 0; /* owner */
1355 *bp++ = 0; /* group */
1356 *bp++ = 0; /* unix mode */
1357 *bp++ = 0; /* segment size */
1358
1359 *bp++ = htonl(pos);
1360 *bp++ = htonl(size);
1361 *bp++ = htonl(i_size);
1362
David Howellsd2ddc772017-11-02 15:27:50 +00001363 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001364 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001365 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells31143d52007-05-09 02:33:46 -07001366}
1367
1368/*
1369 * deliver reply data to an FS.StoreStatus
1370 */
David Howellsd0016482016-08-30 20:42:14 +01001371static int afs_deliver_fs_store_status(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001372{
David Howells97e30432017-11-02 15:27:48 +00001373 struct afs_vnode *vnode = call->reply[0];
David Howells31143d52007-05-09 02:33:46 -07001374 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001375 int ret;
David Howells31143d52007-05-09 02:33:46 -07001376
David Howellsd0016482016-08-30 20:42:14 +01001377 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001378
David Howellsd0016482016-08-30 20:42:14 +01001379 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001380 if (ret < 0)
1381 return ret;
David Howells31143d52007-05-09 02:33:46 -07001382
1383 /* unmarshall the reply once we've received all of it */
David Howells31143d52007-05-09 02:33:46 -07001384 bp = call->buffer;
David Howells5f702c82018-04-06 14:17:25 +01001385 if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
David Howellsdd9fbcb2018-04-06 14:17:24 +01001386 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01001387 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +00001388 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells31143d52007-05-09 02:33:46 -07001389
1390 _leave(" = 0 [done]");
1391 return 0;
1392}
1393
1394/*
1395 * FS.StoreStatus operation type
1396 */
1397static const struct afs_call_type afs_RXFSStoreStatus = {
1398 .name = "FS.StoreStatus",
David Howells025db802017-11-02 15:27:51 +00001399 .op = afs_FS_StoreStatus,
David Howells31143d52007-05-09 02:33:46 -07001400 .deliver = afs_deliver_fs_store_status,
David Howells31143d52007-05-09 02:33:46 -07001401 .destructor = afs_flat_call_destructor,
1402};
1403
1404static const struct afs_call_type afs_RXFSStoreData_as_Status = {
1405 .name = "FS.StoreData",
David Howells025db802017-11-02 15:27:51 +00001406 .op = afs_FS_StoreData,
David Howells31143d52007-05-09 02:33:46 -07001407 .deliver = afs_deliver_fs_store_status,
David Howells31143d52007-05-09 02:33:46 -07001408 .destructor = afs_flat_call_destructor,
1409};
1410
David Howellsb9b1f8d2007-05-10 03:15:21 -07001411static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1412 .name = "FS.StoreData64",
David Howells025db802017-11-02 15:27:51 +00001413 .op = afs_FS_StoreData64,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001414 .deliver = afs_deliver_fs_store_status,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001415 .destructor = afs_flat_call_destructor,
1416};
1417
1418/*
1419 * set the attributes on a very large file, using FS.StoreData rather than
1420 * FS.StoreStatus so as to alter the file size also
1421 */
David Howellsd2ddc772017-11-02 15:27:50 +00001422static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001423{
David Howellsd2ddc772017-11-02 15:27:50 +00001424 struct afs_vnode *vnode = fc->vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001425 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001426 struct afs_net *net = afs_v2net(vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001427 __be32 *bp;
1428
1429 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +00001430 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001431
1432 ASSERT(attr->ia_valid & ATTR_SIZE);
1433
David Howellsf044c882017-11-02 15:27:45 +00001434 call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001435 (4 + 6 + 3 * 2) * 4,
1436 (21 + 6) * 4);
1437 if (!call)
1438 return -ENOMEM;
1439
David Howellsd2ddc772017-11-02 15:27:50 +00001440 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001441 call->reply[0] = vnode;
David Howells0c3a5ac2018-04-06 14:17:24 +01001442 call->expected_version = vnode->status.data_version + 1;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001443
1444 /* marshall the parameters */
1445 bp = call->request;
1446 *bp++ = htonl(FSSTOREDATA64);
1447 *bp++ = htonl(vnode->fid.vid);
1448 *bp++ = htonl(vnode->fid.vnode);
1449 *bp++ = htonl(vnode->fid.unique);
1450
1451 xdr_encode_AFS_StoreStatus(&bp, attr);
1452
1453 *bp++ = 0; /* position of start of write */
1454 *bp++ = 0;
1455 *bp++ = 0; /* size of write */
1456 *bp++ = 0;
1457 *bp++ = htonl(attr->ia_size >> 32); /* new file length */
1458 *bp++ = htonl((u32) attr->ia_size);
1459
David Howellsd2ddc772017-11-02 15:27:50 +00001460 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001461 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001462 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001463}
1464
David Howells31143d52007-05-09 02:33:46 -07001465/*
1466 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
1467 * so as to alter the file size also
1468 */
David Howellsd2ddc772017-11-02 15:27:50 +00001469static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
David Howells31143d52007-05-09 02:33:46 -07001470{
David Howellsd2ddc772017-11-02 15:27:50 +00001471 struct afs_vnode *vnode = fc->vnode;
David Howells31143d52007-05-09 02:33:46 -07001472 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001473 struct afs_net *net = afs_v2net(vnode);
David Howells31143d52007-05-09 02:33:46 -07001474 __be32 *bp;
1475
1476 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +00001477 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howells31143d52007-05-09 02:33:46 -07001478
1479 ASSERT(attr->ia_valid & ATTR_SIZE);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001480 if (attr->ia_size >> 32)
David Howellsd2ddc772017-11-02 15:27:50 +00001481 return afs_fs_setattr_size64(fc, attr);
David Howells31143d52007-05-09 02:33:46 -07001482
David Howellsf044c882017-11-02 15:27:45 +00001483 call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
David Howells31143d52007-05-09 02:33:46 -07001484 (4 + 6 + 3) * 4,
1485 (21 + 6) * 4);
1486 if (!call)
1487 return -ENOMEM;
1488
David Howellsd2ddc772017-11-02 15:27:50 +00001489 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001490 call->reply[0] = vnode;
David Howells0c3a5ac2018-04-06 14:17:24 +01001491 call->expected_version = vnode->status.data_version + 1;
David Howells31143d52007-05-09 02:33:46 -07001492
1493 /* marshall the parameters */
1494 bp = call->request;
1495 *bp++ = htonl(FSSTOREDATA);
1496 *bp++ = htonl(vnode->fid.vid);
1497 *bp++ = htonl(vnode->fid.vnode);
1498 *bp++ = htonl(vnode->fid.unique);
1499
1500 xdr_encode_AFS_StoreStatus(&bp, attr);
1501
1502 *bp++ = 0; /* position of start of write */
1503 *bp++ = 0; /* size of write */
1504 *bp++ = htonl(attr->ia_size); /* new file length */
1505
David Howellsd2ddc772017-11-02 15:27:50 +00001506 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001507 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001508 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells31143d52007-05-09 02:33:46 -07001509}
1510
1511/*
1512 * set the attributes on a file, using FS.StoreData if there's a change in file
1513 * size, and FS.StoreStatus otherwise
1514 */
David Howellsd2ddc772017-11-02 15:27:50 +00001515int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
David Howells31143d52007-05-09 02:33:46 -07001516{
David Howellsd2ddc772017-11-02 15:27:50 +00001517 struct afs_vnode *vnode = fc->vnode;
David Howells31143d52007-05-09 02:33:46 -07001518 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001519 struct afs_net *net = afs_v2net(vnode);
David Howells31143d52007-05-09 02:33:46 -07001520 __be32 *bp;
1521
1522 if (attr->ia_valid & ATTR_SIZE)
David Howellsd2ddc772017-11-02 15:27:50 +00001523 return afs_fs_setattr_size(fc, attr);
David Howells31143d52007-05-09 02:33:46 -07001524
1525 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +00001526 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howells31143d52007-05-09 02:33:46 -07001527
David Howellsf044c882017-11-02 15:27:45 +00001528 call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
David Howells31143d52007-05-09 02:33:46 -07001529 (4 + 6) * 4,
1530 (21 + 6) * 4);
1531 if (!call)
1532 return -ENOMEM;
1533
David Howellsd2ddc772017-11-02 15:27:50 +00001534 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001535 call->reply[0] = vnode;
David Howells0c3a5ac2018-04-06 14:17:24 +01001536 call->expected_version = vnode->status.data_version;
David Howells31143d52007-05-09 02:33:46 -07001537
1538 /* marshall the parameters */
1539 bp = call->request;
1540 *bp++ = htonl(FSSTORESTATUS);
1541 *bp++ = htonl(vnode->fid.vid);
1542 *bp++ = htonl(vnode->fid.vnode);
1543 *bp++ = htonl(vnode->fid.unique);
1544
1545 xdr_encode_AFS_StoreStatus(&bp, attr);
1546
David Howellsd2ddc772017-11-02 15:27:50 +00001547 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001548 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001549 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells31143d52007-05-09 02:33:46 -07001550}
David Howells45222b92007-05-10 22:22:20 -07001551
1552/*
1553 * deliver reply data to an FS.GetVolumeStatus
1554 */
David Howellsd0016482016-08-30 20:42:14 +01001555static int afs_deliver_fs_get_volume_status(struct afs_call *call)
David Howells45222b92007-05-10 22:22:20 -07001556{
1557 const __be32 *bp;
1558 char *p;
1559 int ret;
1560
David Howellsd0016482016-08-30 20:42:14 +01001561 _enter("{%u}", call->unmarshall);
David Howells45222b92007-05-10 22:22:20 -07001562
1563 switch (call->unmarshall) {
1564 case 0:
1565 call->offset = 0;
1566 call->unmarshall++;
1567
1568 /* extract the returned status record */
1569 case 1:
1570 _debug("extract status");
David Howellsd0016482016-08-30 20:42:14 +01001571 ret = afs_extract_data(call, call->buffer,
1572 12 * 4, true);
David Howells372ee162016-08-03 14:11:40 +01001573 if (ret < 0)
1574 return ret;
David Howells45222b92007-05-10 22:22:20 -07001575
1576 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +00001577 xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]);
David Howells45222b92007-05-10 22:22:20 -07001578 call->offset = 0;
1579 call->unmarshall++;
1580
1581 /* extract the volume name length */
1582 case 2:
David Howellsd0016482016-08-30 20:42:14 +01001583 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001584 if (ret < 0)
1585 return ret;
David Howells45222b92007-05-10 22:22:20 -07001586
1587 call->count = ntohl(call->tmp);
1588 _debug("volname length: %u", call->count);
1589 if (call->count >= AFSNAMEMAX)
David Howells5f702c82018-04-06 14:17:25 +01001590 return afs_protocol_error(call, -EBADMSG);
David Howells45222b92007-05-10 22:22:20 -07001591 call->offset = 0;
1592 call->unmarshall++;
1593
1594 /* extract the volume name */
1595 case 3:
1596 _debug("extract volname");
1597 if (call->count > 0) {
David Howells97e30432017-11-02 15:27:48 +00001598 ret = afs_extract_data(call, call->reply[2],
David Howellsd0016482016-08-30 20:42:14 +01001599 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001600 if (ret < 0)
1601 return ret;
David Howells45222b92007-05-10 22:22:20 -07001602 }
1603
David Howells97e30432017-11-02 15:27:48 +00001604 p = call->reply[2];
David Howells45222b92007-05-10 22:22:20 -07001605 p[call->count] = 0;
1606 _debug("volname '%s'", p);
1607
1608 call->offset = 0;
1609 call->unmarshall++;
1610
1611 /* extract the volume name padding */
1612 if ((call->count & 3) == 0) {
1613 call->unmarshall++;
1614 goto no_volname_padding;
1615 }
1616 call->count = 4 - (call->count & 3);
1617
1618 case 4:
David Howellsd0016482016-08-30 20:42:14 +01001619 ret = afs_extract_data(call, call->buffer,
1620 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001621 if (ret < 0)
1622 return ret;
David Howells45222b92007-05-10 22:22:20 -07001623
1624 call->offset = 0;
1625 call->unmarshall++;
1626 no_volname_padding:
1627
1628 /* extract the offline message length */
1629 case 5:
David Howellsd0016482016-08-30 20:42:14 +01001630 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001631 if (ret < 0)
1632 return ret;
David Howells45222b92007-05-10 22:22:20 -07001633
1634 call->count = ntohl(call->tmp);
1635 _debug("offline msg length: %u", call->count);
1636 if (call->count >= AFSNAMEMAX)
David Howells5f702c82018-04-06 14:17:25 +01001637 return afs_protocol_error(call, -EBADMSG);
David Howells45222b92007-05-10 22:22:20 -07001638 call->offset = 0;
1639 call->unmarshall++;
1640
1641 /* extract the offline message */
1642 case 6:
1643 _debug("extract offline");
1644 if (call->count > 0) {
David Howells97e30432017-11-02 15:27:48 +00001645 ret = afs_extract_data(call, call->reply[2],
David Howellsd0016482016-08-30 20:42:14 +01001646 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001647 if (ret < 0)
1648 return ret;
David Howells45222b92007-05-10 22:22:20 -07001649 }
1650
David Howells97e30432017-11-02 15:27:48 +00001651 p = call->reply[2];
David Howells45222b92007-05-10 22:22:20 -07001652 p[call->count] = 0;
1653 _debug("offline '%s'", p);
1654
1655 call->offset = 0;
1656 call->unmarshall++;
1657
1658 /* extract the offline message padding */
1659 if ((call->count & 3) == 0) {
1660 call->unmarshall++;
1661 goto no_offline_padding;
1662 }
1663 call->count = 4 - (call->count & 3);
1664
1665 case 7:
David Howellsd0016482016-08-30 20:42:14 +01001666 ret = afs_extract_data(call, call->buffer,
1667 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001668 if (ret < 0)
1669 return ret;
David Howells45222b92007-05-10 22:22:20 -07001670
1671 call->offset = 0;
1672 call->unmarshall++;
1673 no_offline_padding:
1674
1675 /* extract the message of the day length */
1676 case 8:
David Howellsd0016482016-08-30 20:42:14 +01001677 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001678 if (ret < 0)
1679 return ret;
David Howells45222b92007-05-10 22:22:20 -07001680
1681 call->count = ntohl(call->tmp);
1682 _debug("motd length: %u", call->count);
1683 if (call->count >= AFSNAMEMAX)
David Howells5f702c82018-04-06 14:17:25 +01001684 return afs_protocol_error(call, -EBADMSG);
David Howells45222b92007-05-10 22:22:20 -07001685 call->offset = 0;
1686 call->unmarshall++;
1687
1688 /* extract the message of the day */
1689 case 9:
1690 _debug("extract motd");
1691 if (call->count > 0) {
David Howells97e30432017-11-02 15:27:48 +00001692 ret = afs_extract_data(call, call->reply[2],
David Howellsd0016482016-08-30 20:42:14 +01001693 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001694 if (ret < 0)
1695 return ret;
David Howells45222b92007-05-10 22:22:20 -07001696 }
1697
David Howells97e30432017-11-02 15:27:48 +00001698 p = call->reply[2];
David Howells45222b92007-05-10 22:22:20 -07001699 p[call->count] = 0;
1700 _debug("motd '%s'", p);
1701
1702 call->offset = 0;
1703 call->unmarshall++;
1704
1705 /* extract the message of the day padding */
David Howellsd0016482016-08-30 20:42:14 +01001706 call->count = (4 - (call->count & 3)) & 3;
David Howells45222b92007-05-10 22:22:20 -07001707
1708 case 10:
David Howellsd0016482016-08-30 20:42:14 +01001709 ret = afs_extract_data(call, call->buffer,
1710 call->count, false);
David Howells372ee162016-08-03 14:11:40 +01001711 if (ret < 0)
1712 return ret;
David Howells45222b92007-05-10 22:22:20 -07001713
1714 call->offset = 0;
1715 call->unmarshall++;
David Howells45222b92007-05-10 22:22:20 -07001716 case 11:
David Howells45222b92007-05-10 22:22:20 -07001717 break;
1718 }
1719
David Howells45222b92007-05-10 22:22:20 -07001720 _leave(" = 0 [done]");
1721 return 0;
1722}
1723
1724/*
1725 * destroy an FS.GetVolumeStatus call
1726 */
1727static void afs_get_volume_status_call_destructor(struct afs_call *call)
1728{
David Howells97e30432017-11-02 15:27:48 +00001729 kfree(call->reply[2]);
1730 call->reply[2] = NULL;
David Howells45222b92007-05-10 22:22:20 -07001731 afs_flat_call_destructor(call);
1732}
1733
1734/*
1735 * FS.GetVolumeStatus operation type
1736 */
1737static const struct afs_call_type afs_RXFSGetVolumeStatus = {
1738 .name = "FS.GetVolumeStatus",
David Howells025db802017-11-02 15:27:51 +00001739 .op = afs_FS_GetVolumeStatus,
David Howells45222b92007-05-10 22:22:20 -07001740 .deliver = afs_deliver_fs_get_volume_status,
David Howells45222b92007-05-10 22:22:20 -07001741 .destructor = afs_get_volume_status_call_destructor,
1742};
1743
1744/*
1745 * fetch the status of a volume
1746 */
David Howells8b2a4642017-11-02 15:27:50 +00001747int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
David Howellsd2ddc772017-11-02 15:27:50 +00001748 struct afs_volume_status *vs)
David Howells45222b92007-05-10 22:22:20 -07001749{
David Howellsd2ddc772017-11-02 15:27:50 +00001750 struct afs_vnode *vnode = fc->vnode;
David Howells45222b92007-05-10 22:22:20 -07001751 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001752 struct afs_net *net = afs_v2net(vnode);
David Howells45222b92007-05-10 22:22:20 -07001753 __be32 *bp;
1754 void *tmpbuf;
1755
1756 _enter("");
1757
1758 tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
1759 if (!tmpbuf)
1760 return -ENOMEM;
1761
David Howellsf044c882017-11-02 15:27:45 +00001762 call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
David Howells45222b92007-05-10 22:22:20 -07001763 if (!call) {
1764 kfree(tmpbuf);
1765 return -ENOMEM;
1766 }
1767
David Howellsd2ddc772017-11-02 15:27:50 +00001768 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001769 call->reply[0] = vnode;
1770 call->reply[1] = vs;
1771 call->reply[2] = tmpbuf;
David Howells45222b92007-05-10 22:22:20 -07001772
1773 /* marshall the parameters */
1774 bp = call->request;
1775 bp[0] = htonl(FSGETVOLUMESTATUS);
1776 bp[1] = htonl(vnode->fid.vid);
1777
David Howellsd2ddc772017-11-02 15:27:50 +00001778 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001779 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001780 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells45222b92007-05-10 22:22:20 -07001781}
David Howellse8d6c552007-07-15 23:40:12 -07001782
1783/*
1784 * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1785 */
David Howellsd0016482016-08-30 20:42:14 +01001786static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
David Howellse8d6c552007-07-15 23:40:12 -07001787{
1788 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001789 int ret;
David Howellse8d6c552007-07-15 23:40:12 -07001790
David Howellsd0016482016-08-30 20:42:14 +01001791 _enter("{%u}", call->unmarshall);
David Howellse8d6c552007-07-15 23:40:12 -07001792
David Howellsd0016482016-08-30 20:42:14 +01001793 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001794 if (ret < 0)
1795 return ret;
David Howellse8d6c552007-07-15 23:40:12 -07001796
1797 /* unmarshall the reply once we've received all of it */
1798 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +00001799 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howellse8d6c552007-07-15 23:40:12 -07001800
1801 _leave(" = 0 [done]");
1802 return 0;
1803}
1804
1805/*
1806 * FS.SetLock operation type
1807 */
1808static const struct afs_call_type afs_RXFSSetLock = {
1809 .name = "FS.SetLock",
David Howells025db802017-11-02 15:27:51 +00001810 .op = afs_FS_SetLock,
David Howellse8d6c552007-07-15 23:40:12 -07001811 .deliver = afs_deliver_fs_xxxx_lock,
David Howellse8d6c552007-07-15 23:40:12 -07001812 .destructor = afs_flat_call_destructor,
1813};
1814
1815/*
1816 * FS.ExtendLock operation type
1817 */
1818static const struct afs_call_type afs_RXFSExtendLock = {
1819 .name = "FS.ExtendLock",
David Howells025db802017-11-02 15:27:51 +00001820 .op = afs_FS_ExtendLock,
David Howellse8d6c552007-07-15 23:40:12 -07001821 .deliver = afs_deliver_fs_xxxx_lock,
David Howellse8d6c552007-07-15 23:40:12 -07001822 .destructor = afs_flat_call_destructor,
1823};
1824
1825/*
1826 * FS.ReleaseLock operation type
1827 */
1828static const struct afs_call_type afs_RXFSReleaseLock = {
1829 .name = "FS.ReleaseLock",
David Howells025db802017-11-02 15:27:51 +00001830 .op = afs_FS_ReleaseLock,
David Howellse8d6c552007-07-15 23:40:12 -07001831 .deliver = afs_deliver_fs_xxxx_lock,
David Howellse8d6c552007-07-15 23:40:12 -07001832 .destructor = afs_flat_call_destructor,
1833};
1834
1835/*
David Howellsd2ddc772017-11-02 15:27:50 +00001836 * Set a lock on a file
David Howellse8d6c552007-07-15 23:40:12 -07001837 */
David Howellsd2ddc772017-11-02 15:27:50 +00001838int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
David Howellse8d6c552007-07-15 23:40:12 -07001839{
David Howellsd2ddc772017-11-02 15:27:50 +00001840 struct afs_vnode *vnode = fc->vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001841 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001842 struct afs_net *net = afs_v2net(vnode);
David Howellse8d6c552007-07-15 23:40:12 -07001843 __be32 *bp;
1844
1845 _enter("");
1846
David Howellsf044c882017-11-02 15:27:45 +00001847 call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
David Howellse8d6c552007-07-15 23:40:12 -07001848 if (!call)
1849 return -ENOMEM;
1850
David Howellsd2ddc772017-11-02 15:27:50 +00001851 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001852 call->reply[0] = vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001853
1854 /* marshall the parameters */
1855 bp = call->request;
1856 *bp++ = htonl(FSSETLOCK);
1857 *bp++ = htonl(vnode->fid.vid);
1858 *bp++ = htonl(vnode->fid.vnode);
1859 *bp++ = htonl(vnode->fid.unique);
1860 *bp++ = htonl(type);
1861
David Howellsd2ddc772017-11-02 15:27:50 +00001862 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001863 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001864 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellse8d6c552007-07-15 23:40:12 -07001865}
1866
1867/*
1868 * extend a lock on a file
1869 */
David Howellsd2ddc772017-11-02 15:27:50 +00001870int afs_fs_extend_lock(struct afs_fs_cursor *fc)
David Howellse8d6c552007-07-15 23:40:12 -07001871{
David Howellsd2ddc772017-11-02 15:27:50 +00001872 struct afs_vnode *vnode = fc->vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001873 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001874 struct afs_net *net = afs_v2net(vnode);
David Howellse8d6c552007-07-15 23:40:12 -07001875 __be32 *bp;
1876
1877 _enter("");
1878
David Howellsf044c882017-11-02 15:27:45 +00001879 call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
David Howellse8d6c552007-07-15 23:40:12 -07001880 if (!call)
1881 return -ENOMEM;
1882
David Howellsd2ddc772017-11-02 15:27:50 +00001883 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001884 call->reply[0] = vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001885
1886 /* marshall the parameters */
1887 bp = call->request;
1888 *bp++ = htonl(FSEXTENDLOCK);
1889 *bp++ = htonl(vnode->fid.vid);
1890 *bp++ = htonl(vnode->fid.vnode);
1891 *bp++ = htonl(vnode->fid.unique);
1892
David Howellsd2ddc772017-11-02 15:27:50 +00001893 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001894 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001895 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellse8d6c552007-07-15 23:40:12 -07001896}
1897
1898/*
1899 * release a lock on a file
1900 */
David Howellsd2ddc772017-11-02 15:27:50 +00001901int afs_fs_release_lock(struct afs_fs_cursor *fc)
David Howellse8d6c552007-07-15 23:40:12 -07001902{
David Howellsd2ddc772017-11-02 15:27:50 +00001903 struct afs_vnode *vnode = fc->vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001904 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001905 struct afs_net *net = afs_v2net(vnode);
David Howellse8d6c552007-07-15 23:40:12 -07001906 __be32 *bp;
1907
1908 _enter("");
1909
David Howellsf044c882017-11-02 15:27:45 +00001910 call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
David Howellse8d6c552007-07-15 23:40:12 -07001911 if (!call)
1912 return -ENOMEM;
1913
David Howellsd2ddc772017-11-02 15:27:50 +00001914 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001915 call->reply[0] = vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001916
1917 /* marshall the parameters */
1918 bp = call->request;
1919 *bp++ = htonl(FSRELEASELOCK);
1920 *bp++ = htonl(vnode->fid.vid);
1921 *bp++ = htonl(vnode->fid.vnode);
1922 *bp++ = htonl(vnode->fid.unique);
1923
David Howellsd2ddc772017-11-02 15:27:50 +00001924 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001925 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001926 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsc435ee32017-11-02 15:27:49 +00001927}
1928
1929/*
1930 * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1931 */
1932static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1933{
1934 return afs_transfer_reply(call);
1935}
1936
1937/*
1938 * FS.GiveUpAllCallBacks operation type
1939 */
1940static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1941 .name = "FS.GiveUpAllCallBacks",
David Howells025db802017-11-02 15:27:51 +00001942 .op = afs_FS_GiveUpAllCallBacks,
David Howellsc435ee32017-11-02 15:27:49 +00001943 .deliver = afs_deliver_fs_give_up_all_callbacks,
1944 .destructor = afs_flat_call_destructor,
1945};
1946
1947/*
1948 * Flush all the callbacks we have on a server.
1949 */
David Howellsd2ddc772017-11-02 15:27:50 +00001950int afs_fs_give_up_all_callbacks(struct afs_net *net,
1951 struct afs_server *server,
David Howells8b2a4642017-11-02 15:27:50 +00001952 struct afs_addr_cursor *ac,
David Howellsd2ddc772017-11-02 15:27:50 +00001953 struct key *key)
David Howellsc435ee32017-11-02 15:27:49 +00001954{
1955 struct afs_call *call;
1956 __be32 *bp;
1957
1958 _enter("");
1959
David Howellsd2ddc772017-11-02 15:27:50 +00001960 call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
David Howellsc435ee32017-11-02 15:27:49 +00001961 if (!call)
1962 return -ENOMEM;
1963
1964 call->key = key;
1965
1966 /* marshall the parameters */
1967 bp = call->request;
1968 *bp++ = htonl(FSGIVEUPALLCALLBACKS);
1969
1970 /* Can't take a ref on server */
David Howellsd2ddc772017-11-02 15:27:50 +00001971 return afs_make_call(ac, call, GFP_NOFS, false);
1972}
1973
1974/*
1975 * Deliver reply data to an FS.GetCapabilities operation.
1976 */
1977static int afs_deliver_fs_get_capabilities(struct afs_call *call)
1978{
1979 u32 count;
1980 int ret;
1981
1982 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
1983
1984again:
1985 switch (call->unmarshall) {
1986 case 0:
1987 call->offset = 0;
1988 call->unmarshall++;
1989
1990 /* Extract the capabilities word count */
1991 case 1:
1992 ret = afs_extract_data(call, &call->tmp,
1993 1 * sizeof(__be32),
1994 true);
1995 if (ret < 0)
1996 return ret;
1997
1998 count = ntohl(call->tmp);
1999
2000 call->count = count;
2001 call->count2 = count;
2002 call->offset = 0;
2003 call->unmarshall++;
2004
2005 /* Extract capabilities words */
2006 case 2:
2007 count = min(call->count, 16U);
2008 ret = afs_extract_data(call, call->buffer,
2009 count * sizeof(__be32),
2010 call->count > 16);
2011 if (ret < 0)
2012 return ret;
2013
2014 /* TODO: Examine capabilities */
2015
2016 call->count -= count;
2017 if (call->count > 0)
2018 goto again;
2019 call->offset = 0;
2020 call->unmarshall++;
2021 break;
2022 }
2023
2024 _leave(" = 0 [done]");
2025 return 0;
2026}
2027
2028/*
2029 * FS.GetCapabilities operation type
2030 */
2031static const struct afs_call_type afs_RXFSGetCapabilities = {
2032 .name = "FS.GetCapabilities",
David Howells025db802017-11-02 15:27:51 +00002033 .op = afs_FS_GetCapabilities,
David Howellsd2ddc772017-11-02 15:27:50 +00002034 .deliver = afs_deliver_fs_get_capabilities,
2035 .destructor = afs_flat_call_destructor,
2036};
2037
2038/*
2039 * Probe a fileserver for the capabilities that it supports. This can
2040 * return up to 196 words.
2041 */
2042int afs_fs_get_capabilities(struct afs_net *net,
2043 struct afs_server *server,
2044 struct afs_addr_cursor *ac,
2045 struct key *key)
2046{
2047 struct afs_call *call;
2048 __be32 *bp;
2049
2050 _enter("");
2051
2052 call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
2053 if (!call)
2054 return -ENOMEM;
2055
2056 call->key = key;
2057
2058 /* marshall the parameters */
2059 bp = call->request;
2060 *bp++ = htonl(FSGETCAPABILITIES);
2061
2062 /* Can't take a ref on server */
David Howells025db802017-11-02 15:27:51 +00002063 trace_afs_make_fs_call(call, NULL);
David Howellsd2ddc772017-11-02 15:27:50 +00002064 return afs_make_call(ac, call, GFP_NOFS, false);
David Howellse8d6c552007-07-15 23:40:12 -07002065}
David Howells5cf9dd52018-04-09 21:12:31 +01002066
2067/*
2068 * Deliver reply data to an FS.FetchStatus with no vnode.
2069 */
2070static int afs_deliver_fs_fetch_status(struct afs_call *call)
2071{
2072 struct afs_file_status *status = call->reply[1];
2073 struct afs_callback *callback = call->reply[2];
2074 struct afs_volsync *volsync = call->reply[3];
2075 struct afs_vnode *vnode = call->reply[0];
2076 const __be32 *bp;
2077 int ret;
2078
2079 ret = afs_transfer_reply(call);
2080 if (ret < 0)
2081 return ret;
2082
2083 _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
2084
2085 /* unmarshall the reply once we've received all of it */
2086 bp = call->buffer;
David Howells5f702c82018-04-06 14:17:25 +01002087 xdr_decode_AFSFetchStatus(call, &bp, status, vnode,
David Howells0c3a5ac2018-04-06 14:17:24 +01002088 &call->expected_version, NULL);
David Howells5cf9dd52018-04-09 21:12:31 +01002089 callback[call->count].version = ntohl(bp[0]);
2090 callback[call->count].expiry = ntohl(bp[1]);
2091 callback[call->count].type = ntohl(bp[2]);
2092 if (vnode)
2093 xdr_decode_AFSCallBack(call, vnode, &bp);
2094 else
2095 bp += 3;
2096 if (volsync)
2097 xdr_decode_AFSVolSync(&bp, volsync);
2098
2099 _leave(" = 0 [done]");
2100 return 0;
2101}
2102
2103/*
2104 * FS.FetchStatus operation type
2105 */
2106static const struct afs_call_type afs_RXFSFetchStatus = {
2107 .name = "FS.FetchStatus",
2108 .op = afs_FS_FetchStatus,
2109 .deliver = afs_deliver_fs_fetch_status,
2110 .destructor = afs_flat_call_destructor,
2111};
2112
2113/*
2114 * Fetch the status information for a fid without needing a vnode handle.
2115 */
2116int afs_fs_fetch_status(struct afs_fs_cursor *fc,
2117 struct afs_net *net,
2118 struct afs_fid *fid,
2119 struct afs_file_status *status,
2120 struct afs_callback *callback,
2121 struct afs_volsync *volsync)
2122{
2123 struct afs_call *call;
2124 __be32 *bp;
2125
2126 _enter(",%x,{%x:%u},,",
2127 key_serial(fc->key), fid->vid, fid->vnode);
2128
2129 call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
2130 if (!call) {
2131 fc->ac.error = -ENOMEM;
2132 return -ENOMEM;
2133 }
2134
2135 call->key = fc->key;
2136 call->reply[0] = NULL; /* vnode for fid[0] */
2137 call->reply[1] = status;
2138 call->reply[2] = callback;
2139 call->reply[3] = volsync;
David Howells0c3a5ac2018-04-06 14:17:24 +01002140 call->expected_version = 1; /* vnode->status.data_version */
David Howells5cf9dd52018-04-09 21:12:31 +01002141
2142 /* marshall the parameters */
2143 bp = call->request;
2144 bp[0] = htonl(FSFETCHSTATUS);
2145 bp[1] = htonl(fid->vid);
2146 bp[2] = htonl(fid->vnode);
2147 bp[3] = htonl(fid->unique);
2148
2149 call->cb_break = fc->cb_break;
2150 afs_use_fs_server(call, fc->cbi);
2151 trace_afs_make_fs_call(call, fid);
2152 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
2153}
2154
2155/*
2156 * Deliver reply data to an FS.InlineBulkStatus call
2157 */
2158static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
2159{
2160 struct afs_file_status *statuses;
2161 struct afs_callback *callbacks;
2162 struct afs_vnode *vnode = call->reply[0];
2163 const __be32 *bp;
2164 u32 tmp;
2165 int ret;
2166
2167 _enter("{%u}", call->unmarshall);
2168
2169 switch (call->unmarshall) {
2170 case 0:
2171 call->offset = 0;
2172 call->unmarshall++;
2173
2174 /* Extract the file status count and array in two steps */
2175 case 1:
2176 _debug("extract status count");
2177 ret = afs_extract_data(call, &call->tmp, 4, true);
2178 if (ret < 0)
2179 return ret;
2180
2181 tmp = ntohl(call->tmp);
2182 _debug("status count: %u/%u", tmp, call->count2);
2183 if (tmp != call->count2)
David Howells5f702c82018-04-06 14:17:25 +01002184 return afs_protocol_error(call, -EBADMSG);
David Howells5cf9dd52018-04-09 21:12:31 +01002185
2186 call->count = 0;
2187 call->unmarshall++;
2188 more_counts:
2189 call->offset = 0;
2190
2191 case 2:
2192 _debug("extract status array %u", call->count);
2193 ret = afs_extract_data(call, call->buffer, 21 * 4, true);
2194 if (ret < 0)
2195 return ret;
2196
2197 bp = call->buffer;
2198 statuses = call->reply[1];
David Howells5f702c82018-04-06 14:17:25 +01002199 if (xdr_decode_AFSFetchStatus(call, &bp, &statuses[call->count],
David Howellsdd9fbcb2018-04-06 14:17:24 +01002200 call->count == 0 ? vnode : NULL,
2201 NULL, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01002202 return afs_protocol_error(call, -EBADMSG);
David Howells5cf9dd52018-04-09 21:12:31 +01002203
2204 call->count++;
2205 if (call->count < call->count2)
2206 goto more_counts;
2207
2208 call->count = 0;
2209 call->unmarshall++;
2210 call->offset = 0;
2211
2212 /* Extract the callback count and array in two steps */
2213 case 3:
2214 _debug("extract CB count");
2215 ret = afs_extract_data(call, &call->tmp, 4, true);
2216 if (ret < 0)
2217 return ret;
2218
2219 tmp = ntohl(call->tmp);
2220 _debug("CB count: %u", tmp);
2221 if (tmp != call->count2)
David Howells5f702c82018-04-06 14:17:25 +01002222 return afs_protocol_error(call, -EBADMSG);
David Howells5cf9dd52018-04-09 21:12:31 +01002223 call->count = 0;
2224 call->unmarshall++;
2225 more_cbs:
2226 call->offset = 0;
2227
2228 case 4:
2229 _debug("extract CB array");
2230 ret = afs_extract_data(call, call->buffer, 3 * 4, true);
2231 if (ret < 0)
2232 return ret;
2233
2234 _debug("unmarshall CB array");
2235 bp = call->buffer;
2236 callbacks = call->reply[2];
2237 callbacks[call->count].version = ntohl(bp[0]);
2238 callbacks[call->count].expiry = ntohl(bp[1]);
2239 callbacks[call->count].type = ntohl(bp[2]);
2240 statuses = call->reply[1];
2241 if (call->count == 0 && vnode && statuses[0].abort_code == 0)
2242 xdr_decode_AFSCallBack(call, vnode, &bp);
2243 call->count++;
2244 if (call->count < call->count2)
2245 goto more_cbs;
2246
2247 call->offset = 0;
2248 call->unmarshall++;
2249
2250 case 5:
2251 ret = afs_extract_data(call, call->buffer, 6 * 4, false);
2252 if (ret < 0)
2253 return ret;
2254
2255 bp = call->buffer;
2256 if (call->reply[3])
2257 xdr_decode_AFSVolSync(&bp, call->reply[3]);
2258
2259 call->offset = 0;
2260 call->unmarshall++;
2261
2262 case 6:
2263 break;
2264 }
2265
2266 _leave(" = 0 [done]");
2267 return 0;
2268}
2269
2270/*
2271 * FS.InlineBulkStatus operation type
2272 */
2273static const struct afs_call_type afs_RXFSInlineBulkStatus = {
2274 .name = "FS.InlineBulkStatus",
2275 .op = afs_FS_InlineBulkStatus,
2276 .deliver = afs_deliver_fs_inline_bulk_status,
2277 .destructor = afs_flat_call_destructor,
2278};
2279
2280/*
2281 * Fetch the status information for up to 50 files
2282 */
2283int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
2284 struct afs_net *net,
2285 struct afs_fid *fids,
2286 struct afs_file_status *statuses,
2287 struct afs_callback *callbacks,
2288 unsigned int nr_fids,
2289 struct afs_volsync *volsync)
2290{
2291 struct afs_call *call;
2292 __be32 *bp;
2293 int i;
2294
2295 _enter(",%x,{%x:%u},%u",
2296 key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids);
2297
2298 call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus,
2299 (2 + nr_fids * 3) * 4,
2300 21 * 4);
2301 if (!call) {
2302 fc->ac.error = -ENOMEM;
2303 return -ENOMEM;
2304 }
2305
2306 call->key = fc->key;
2307 call->reply[0] = NULL; /* vnode for fid[0] */
2308 call->reply[1] = statuses;
2309 call->reply[2] = callbacks;
2310 call->reply[3] = volsync;
2311 call->count2 = nr_fids;
2312
2313 /* marshall the parameters */
2314 bp = call->request;
2315 *bp++ = htonl(FSINLINEBULKSTATUS);
2316 *bp++ = htonl(nr_fids);
2317 for (i = 0; i < nr_fids; i++) {
2318 *bp++ = htonl(fids[i].vid);
2319 *bp++ = htonl(fids[i].vnode);
2320 *bp++ = htonl(fids[i].unique);
2321 }
2322
2323 call->cb_break = fc->cb_break;
2324 afs_use_fs_server(call, fc->cbi);
2325 trace_afs_make_fs_call(call, &fids[0]);
2326 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
2327}