blob: 2a80bbcc31f9e42d55fe41524579e28bf7157256 [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;
David Howells684b0f62018-05-10 21:51:47 +0100137 bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
David Howellsdd9fbcb2018-04-06 14:17:24 +0100138 u64 data_version, size;
139 u32 type, abort_code;
140 u8 flags = 0;
David Howellsdd9fbcb2018-04-06 14:17:24 +0100141
David Howells684b0f62018-05-10 21:51:47 +0100142 abort_code = ntohl(xdr->abort_code);
143
David Howellsdd9fbcb2018-04-06 14:17:24 +0100144 if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
David Howells684b0f62018-05-10 21:51:47 +0100145 if (xdr->if_version == htonl(0) &&
146 abort_code != 0 &&
147 inline_error) {
148 /* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
149 * whereby it doesn't set the interface version in the error
150 * case.
151 */
152 status->abort_code = abort_code;
Al Virode52cf92018-06-02 18:08:11 -0400153 return 0;
David Howells684b0f62018-05-10 21:51:47 +0100154 }
155
David Howellsdd9fbcb2018-04-06 14:17:24 +0100156 pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
157 goto bad;
158 }
159
David Howells684b0f62018-05-10 21:51:47 +0100160 if (abort_code != 0 && inline_error) {
161 status->abort_code = abort_code;
Al Virode52cf92018-06-02 18:08:11 -0400162 return 0;
David Howells684b0f62018-05-10 21:51:47 +0100163 }
164
David Howellsdd9fbcb2018-04-06 14:17:24 +0100165 type = ntohl(xdr->type);
David Howellsdd9fbcb2018-04-06 14:17:24 +0100166 switch (type) {
167 case AFS_FTYPE_FILE:
168 case AFS_FTYPE_DIR:
169 case AFS_FTYPE_SYMLINK:
170 if (type != status->type &&
171 vnode &&
172 !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
173 pr_warning("Vnode %x:%x:%x changed type %u to %u\n",
174 vnode->fid.vid,
175 vnode->fid.vnode,
176 vnode->fid.unique,
177 status->type, type);
178 goto bad;
179 }
180 status->type = type;
181 break;
David Howellsdd9fbcb2018-04-06 14:17:24 +0100182 default:
183 goto bad;
184 }
185
186#define EXTRACT_M(FIELD) \
187 do { \
188 u32 x = ntohl(xdr->FIELD); \
189 if (status->FIELD != x) { \
190 flags |= AFS_VNODE_META_CHANGED; \
191 status->FIELD = x; \
192 } \
193 } while (0)
194
195 EXTRACT_M(nlink);
196 EXTRACT_M(author);
197 EXTRACT_M(owner);
198 EXTRACT_M(caller_access); /* call ticket dependent */
199 EXTRACT_M(anon_access);
200 EXTRACT_M(mode);
201 EXTRACT_M(group);
202
203 status->mtime_client = ntohl(xdr->mtime_client);
204 status->mtime_server = ntohl(xdr->mtime_server);
205 status->lock_count = ntohl(xdr->lock_count);
206
207 size = (u64)ntohl(xdr->size_lo);
208 size |= (u64)ntohl(xdr->size_hi) << 32;
David Howells63a46812018-04-06 14:17:25 +0100209 status->size = size;
David Howellsdd9fbcb2018-04-06 14:17:24 +0100210
211 data_version = (u64)ntohl(xdr->data_version_lo);
212 data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
213 if (data_version != status->data_version) {
214 status->data_version = data_version;
215 flags |= AFS_VNODE_DATA_CHANGED;
216 }
David Howellsf3ddee82018-04-06 14:17:25 +0100217
218 if (read_req) {
219 read_req->data_version = data_version;
220 read_req->file_size = size;
221 }
David Howellsdd9fbcb2018-04-06 14:17:24 +0100222
223 *_bp = (const void *)*_bp + sizeof(*xdr);
224
225 if (vnode) {
226 if (test_bit(AFS_VNODE_UNSET, &vnode->flags))
227 flags |= AFS_VNODE_NOT_YET_SET;
228 afs_update_inode_from_status(vnode, status, expected_version,
229 flags);
230 }
231
David Howellsc875c762018-05-23 11:32:06 +0100232 return 0;
David Howellsdd9fbcb2018-04-06 14:17:24 +0100233
234bad:
235 xdr_dump_bad(*_bp);
David Howellsc875c762018-05-23 11:32:06 +0100236 return afs_protocol_error(call, -EBADMSG);
237}
238
239/*
240 * Decode the file status. We need to lock the target vnode if we're going to
241 * update its status so that stat() sees the attributes update atomically.
242 */
243static int afs_decode_status(struct afs_call *call,
244 const __be32 **_bp,
245 struct afs_file_status *status,
246 struct afs_vnode *vnode,
247 const afs_dataversion_t *expected_version,
248 struct afs_read *read_req)
249{
250 int ret;
251
252 if (!vnode)
253 return xdr_decode_AFSFetchStatus(call, _bp, status, vnode,
254 expected_version, read_req);
255
256 write_seqlock(&vnode->cb_lock);
257 ret = xdr_decode_AFSFetchStatus(call, _bp, status, vnode,
258 expected_version, read_req);
259 write_sequnlock(&vnode->cb_lock);
260 return ret;
David Howellsec268152007-04-26 15:49:28 -0700261}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263/*
David Howells08e0e7c2007-04-26 15:55:03 -0700264 * decode an AFSCallBack block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 */
David Howellsc435ee32017-11-02 15:27:49 +0000266static void xdr_decode_AFSCallBack(struct afs_call *call,
267 struct afs_vnode *vnode,
268 const __be32 **_bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
David Howellsd2ddc772017-11-02 15:27:50 +0000270 struct afs_cb_interest *old, *cbi = call->cbi;
David Howells08e0e7c2007-04-26 15:55:03 -0700271 const __be32 *bp = *_bp;
David Howellsc435ee32017-11-02 15:27:49 +0000272 u32 cb_expiry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
David Howellsc435ee32017-11-02 15:27:49 +0000274 write_seqlock(&vnode->cb_lock);
275
David Howells68251f02018-05-12 22:31:33 +0100276 if (call->cb_break == afs_cb_break_sum(vnode, cbi)) {
David Howellsc435ee32017-11-02 15:27:49 +0000277 vnode->cb_version = ntohl(*bp++);
278 cb_expiry = ntohl(*bp++);
279 vnode->cb_type = ntohl(*bp++);
280 vnode->cb_expires_at = cb_expiry + ktime_get_real_seconds();
David Howellsd2ddc772017-11-02 15:27:50 +0000281 old = vnode->cb_interest;
282 if (old != call->cbi) {
283 vnode->cb_interest = cbi;
284 cbi = old;
285 }
David Howellsc435ee32017-11-02 15:27:49 +0000286 set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
287 } else {
288 bp += 3;
289 }
290
291 write_sequnlock(&vnode->cb_lock);
David Howellsd2ddc772017-11-02 15:27:50 +0000292 call->cbi = cbi;
David Howells08e0e7c2007-04-26 15:55:03 -0700293 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700294}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
David Howells260a9802007-04-26 15:59:35 -0700296static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
297 struct afs_callback *cb)
298{
299 const __be32 *bp = *_bp;
300
301 cb->version = ntohl(*bp++);
302 cb->expiry = ntohl(*bp++);
303 cb->type = ntohl(*bp++);
304 *_bp = bp;
305}
306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307/*
David Howells08e0e7c2007-04-26 15:55:03 -0700308 * decode an AFSVolSync block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 */
David Howells08e0e7c2007-04-26 15:55:03 -0700310static void xdr_decode_AFSVolSync(const __be32 **_bp,
311 struct afs_volsync *volsync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
David Howells08e0e7c2007-04-26 15:55:03 -0700313 const __be32 *bp = *_bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
David Howells08e0e7c2007-04-26 15:55:03 -0700315 volsync->creation = ntohl(*bp++);
316 bp++; /* spare2 */
317 bp++; /* spare3 */
318 bp++; /* spare4 */
319 bp++; /* spare5 */
320 bp++; /* spare6 */
321 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700322}
David Howells08e0e7c2007-04-26 15:55:03 -0700323
324/*
David Howells31143d52007-05-09 02:33:46 -0700325 * encode the requested attributes into an AFSStoreStatus block
326 */
327static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
328{
329 __be32 *bp = *_bp;
330 u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
331
332 mask = 0;
333 if (attr->ia_valid & ATTR_MTIME) {
334 mask |= AFS_SET_MTIME;
335 mtime = attr->ia_mtime.tv_sec;
336 }
337
338 if (attr->ia_valid & ATTR_UID) {
339 mask |= AFS_SET_OWNER;
Eric W. Biedermana0a53862012-02-07 16:20:48 -0800340 owner = from_kuid(&init_user_ns, attr->ia_uid);
David Howells31143d52007-05-09 02:33:46 -0700341 }
342
343 if (attr->ia_valid & ATTR_GID) {
344 mask |= AFS_SET_GROUP;
Eric W. Biedermana0a53862012-02-07 16:20:48 -0800345 group = from_kgid(&init_user_ns, attr->ia_gid);
David Howells31143d52007-05-09 02:33:46 -0700346 }
347
348 if (attr->ia_valid & ATTR_MODE) {
349 mask |= AFS_SET_MODE;
350 mode = attr->ia_mode & S_IALLUGO;
351 }
352
353 *bp++ = htonl(mask);
354 *bp++ = htonl(mtime);
355 *bp++ = htonl(owner);
356 *bp++ = htonl(group);
357 *bp++ = htonl(mode);
358 *bp++ = 0; /* segment size */
359 *_bp = bp;
360}
361
362/*
David Howells45222b92007-05-10 22:22:20 -0700363 * decode an AFSFetchVolumeStatus block
364 */
365static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
366 struct afs_volume_status *vs)
367{
368 const __be32 *bp = *_bp;
369
370 vs->vid = ntohl(*bp++);
371 vs->parent_id = ntohl(*bp++);
372 vs->online = ntohl(*bp++);
373 vs->in_service = ntohl(*bp++);
374 vs->blessed = ntohl(*bp++);
375 vs->needs_salvage = ntohl(*bp++);
376 vs->type = ntohl(*bp++);
377 vs->min_quota = ntohl(*bp++);
378 vs->max_quota = ntohl(*bp++);
379 vs->blocks_in_use = ntohl(*bp++);
380 vs->part_blocks_avail = ntohl(*bp++);
381 vs->part_max_blocks = ntohl(*bp++);
382 *_bp = bp;
383}
384
385/*
David Howells08e0e7c2007-04-26 15:55:03 -0700386 * deliver reply data to an FS.FetchStatus
387 */
David Howells5cf9dd52018-04-09 21:12:31 +0100388static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
David Howells08e0e7c2007-04-26 15:55:03 -0700389{
David Howells97e30432017-11-02 15:27:48 +0000390 struct afs_vnode *vnode = call->reply[0];
David Howells08e0e7c2007-04-26 15:55:03 -0700391 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100392 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700393
David Howellsd0016482016-08-30 20:42:14 +0100394 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100395 if (ret < 0)
396 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700397
David Howellsc435ee32017-11-02 15:27:49 +0000398 _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
399
David Howells08e0e7c2007-04-26 15:55:03 -0700400 /* unmarshall the reply once we've received all of it */
401 bp = call->buffer;
David Howellsc875c762018-05-23 11:32:06 +0100402 if (afs_decode_status(call, &bp, &vnode->status, vnode,
403 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100404 return afs_protocol_error(call, -EBADMSG);
David Howellsc435ee32017-11-02 15:27:49 +0000405 xdr_decode_AFSCallBack(call, vnode, &bp);
David Howells97e30432017-11-02 15:27:48 +0000406 if (call->reply[1])
407 xdr_decode_AFSVolSync(&bp, call->reply[1]);
David Howells08e0e7c2007-04-26 15:55:03 -0700408
409 _leave(" = 0 [done]");
410 return 0;
411}
412
413/*
414 * FS.FetchStatus operation type
415 */
David Howells5cf9dd52018-04-09 21:12:31 +0100416static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
417 .name = "FS.FetchStatus(vnode)",
David Howells025db802017-11-02 15:27:51 +0000418 .op = afs_FS_FetchStatus,
David Howells5cf9dd52018-04-09 21:12:31 +0100419 .deliver = afs_deliver_fs_fetch_status_vnode,
David Howells08e0e7c2007-04-26 15:55:03 -0700420 .destructor = afs_flat_call_destructor,
421};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423/*
424 * fetch the status information for a file
425 */
David Howells0c3a5ac2018-04-06 14:17:24 +0100426int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync,
427 bool new_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
David Howellsd2ddc772017-11-02 15:27:50 +0000429 struct afs_vnode *vnode = fc->vnode;
David Howells08e0e7c2007-04-26 15:55:03 -0700430 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000431 struct afs_net *net = afs_v2net(vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 __be32 *bp;
433
David Howells416351f2007-05-09 02:33:45 -0700434 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +0000435 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
David Howells5cf9dd52018-04-09 21:12:31 +0100437 call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode,
438 16, (21 + 3 + 6) * 4);
David Howellsd2ddc772017-11-02 15:27:50 +0000439 if (!call) {
440 fc->ac.error = -ENOMEM;
David Howells08e0e7c2007-04-26 15:55:03 -0700441 return -ENOMEM;
David Howellsd2ddc772017-11-02 15:27:50 +0000442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
David Howellsd2ddc772017-11-02 15:27:50 +0000444 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000445 call->reply[0] = vnode;
446 call->reply[1] = volsync;
David Howells0c3a5ac2018-04-06 14:17:24 +0100447 call->expected_version = new_inode ? 1 : vnode->status.data_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700450 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 bp[0] = htonl(FSFETCHSTATUS);
452 bp[1] = htonl(vnode->fid.vid);
453 bp[2] = htonl(vnode->fid.vnode);
454 bp[3] = htonl(vnode->fid.unique);
455
David Howellsd2ddc772017-11-02 15:27:50 +0000456 call->cb_break = fc->cb_break;
457 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000458 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000459 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsec268152007-04-26 15:49:28 -0700460}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462/*
David Howells08e0e7c2007-04-26 15:55:03 -0700463 * deliver reply data to an FS.FetchData
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 */
David Howellsd0016482016-08-30 20:42:14 +0100465static int afs_deliver_fs_fetch_data(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
David Howells97e30432017-11-02 15:27:48 +0000467 struct afs_vnode *vnode = call->reply[0];
468 struct afs_read *req = call->reply[2];
David Howells08e0e7c2007-04-26 15:55:03 -0700469 const __be32 *bp;
David Howells196ee9c2017-01-05 10:38:34 +0000470 unsigned int size;
David Howells08e0e7c2007-04-26 15:55:03 -0700471 void *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700473
David Howells6a0e3992017-03-16 16:27:46 +0000474 _enter("{%u,%zu/%u;%llu/%llu}",
David Howells196ee9c2017-01-05 10:38:34 +0000475 call->unmarshall, call->offset, call->count,
476 req->remain, req->actual_len);
David Howells08e0e7c2007-04-26 15:55:03 -0700477
478 switch (call->unmarshall) {
479 case 0:
David Howells196ee9c2017-01-05 10:38:34 +0000480 req->actual_len = 0;
David Howells08e0e7c2007-04-26 15:55:03 -0700481 call->offset = 0;
482 call->unmarshall++;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700483 if (call->operation_ID != FSFETCHDATA64) {
484 call->unmarshall++;
485 goto no_msw;
486 }
David Howells08e0e7c2007-04-26 15:55:03 -0700487
David Howellsb9b1f8d2007-05-10 03:15:21 -0700488 /* extract the upper part of the returned data length of an
489 * FSFETCHDATA64 op (which should always be 0 using this
490 * client) */
David Howells08e0e7c2007-04-26 15:55:03 -0700491 case 1:
David Howellsb9b1f8d2007-05-10 03:15:21 -0700492 _debug("extract data length (MSW)");
David Howellsd0016482016-08-30 20:42:14 +0100493 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +0100494 if (ret < 0)
495 return ret;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700496
David Howells196ee9c2017-01-05 10:38:34 +0000497 req->actual_len = ntohl(call->tmp);
498 req->actual_len <<= 32;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700499 call->offset = 0;
500 call->unmarshall++;
501
502 no_msw:
503 /* extract the returned data length */
504 case 2:
David Howells08e0e7c2007-04-26 15:55:03 -0700505 _debug("extract data length");
David Howellsd0016482016-08-30 20:42:14 +0100506 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +0100507 if (ret < 0)
508 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700509
David Howells196ee9c2017-01-05 10:38:34 +0000510 req->actual_len |= ntohl(call->tmp);
511 _debug("DATA length: %llu", req->actual_len);
David Howells196ee9c2017-01-05 10:38:34 +0000512
513 req->remain = req->actual_len;
514 call->offset = req->pos & (PAGE_SIZE - 1);
515 req->index = 0;
516 if (req->actual_len == 0)
517 goto no_more_data;
David Howells08e0e7c2007-04-26 15:55:03 -0700518 call->unmarshall++;
519
David Howells196ee9c2017-01-05 10:38:34 +0000520 begin_page:
David Howells6db3ac32017-03-16 16:27:44 +0000521 ASSERTCMP(req->index, <, req->nr_pages);
David Howells196ee9c2017-01-05 10:38:34 +0000522 if (req->remain > PAGE_SIZE - call->offset)
523 size = PAGE_SIZE - call->offset;
524 else
525 size = req->remain;
526 call->count = call->offset + size;
527 ASSERTCMP(call->count, <=, PAGE_SIZE);
528 req->remain -= size;
529
David Howells08e0e7c2007-04-26 15:55:03 -0700530 /* extract the returned data */
David Howellsb9b1f8d2007-05-10 03:15:21 -0700531 case 3:
David Howells6a0e3992017-03-16 16:27:46 +0000532 _debug("extract data %llu/%llu %zu/%u",
David Howells196ee9c2017-01-05 10:38:34 +0000533 req->remain, req->actual_len, call->offset, call->count);
534
535 buffer = kmap(req->pages[req->index]);
536 ret = afs_extract_data(call, buffer, call->count, true);
537 kunmap(req->pages[req->index]);
538 if (ret < 0)
539 return ret;
540 if (call->offset == PAGE_SIZE) {
541 if (req->page_done)
542 req->page_done(call, req);
David Howells29f06982017-03-16 16:27:46 +0000543 req->index++;
David Howells196ee9c2017-01-05 10:38:34 +0000544 if (req->remain > 0) {
David Howells196ee9c2017-01-05 10:38:34 +0000545 call->offset = 0;
David Howellse8e581a2017-03-16 16:27:44 +0000546 if (req->index >= req->nr_pages) {
547 call->unmarshall = 4;
David Howells6db3ac32017-03-16 16:27:44 +0000548 goto begin_discard;
David Howellse8e581a2017-03-16 16:27:44 +0000549 }
David Howells196ee9c2017-01-05 10:38:34 +0000550 goto begin_page;
551 }
David Howells08e0e7c2007-04-26 15:55:03 -0700552 }
David Howells6db3ac32017-03-16 16:27:44 +0000553 goto no_more_data;
554
555 /* Discard any excess data the server gave us */
556 begin_discard:
557 case 4:
David Howells6a0e3992017-03-16 16:27:46 +0000558 size = min_t(loff_t, sizeof(afs_discard_buffer), req->remain);
David Howells6db3ac32017-03-16 16:27:44 +0000559 call->count = size;
David Howells6a0e3992017-03-16 16:27:46 +0000560 _debug("extract discard %llu/%llu %zu/%u",
David Howells6db3ac32017-03-16 16:27:44 +0000561 req->remain, req->actual_len, call->offset, call->count);
562
563 call->offset = 0;
564 ret = afs_extract_data(call, afs_discard_buffer, call->count, true);
565 req->remain -= call->offset;
566 if (ret < 0)
567 return ret;
568 if (req->remain > 0)
569 goto begin_discard;
David Howells08e0e7c2007-04-26 15:55:03 -0700570
David Howells196ee9c2017-01-05 10:38:34 +0000571 no_more_data:
David Howells08e0e7c2007-04-26 15:55:03 -0700572 call->offset = 0;
David Howells6db3ac32017-03-16 16:27:44 +0000573 call->unmarshall = 5;
David Howells08e0e7c2007-04-26 15:55:03 -0700574
575 /* extract the metadata */
David Howells6db3ac32017-03-16 16:27:44 +0000576 case 5:
David Howellsd0016482016-08-30 20:42:14 +0100577 ret = afs_extract_data(call, call->buffer,
578 (21 + 3 + 6) * 4, false);
David Howells372ee162016-08-03 14:11:40 +0100579 if (ret < 0)
580 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700581
582 bp = call->buffer;
David Howellsc875c762018-05-23 11:32:06 +0100583 if (afs_decode_status(call, &bp, &vnode->status, vnode,
584 &vnode->status.data_version, req) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100585 return afs_protocol_error(call, -EBADMSG);
David Howellsc435ee32017-11-02 15:27:49 +0000586 xdr_decode_AFSCallBack(call, vnode, &bp);
David Howells97e30432017-11-02 15:27:48 +0000587 if (call->reply[1])
588 xdr_decode_AFSVolSync(&bp, call->reply[1]);
David Howells08e0e7c2007-04-26 15:55:03 -0700589
590 call->offset = 0;
591 call->unmarshall++;
592
David Howells6db3ac32017-03-16 16:27:44 +0000593 case 6:
David Howells08e0e7c2007-04-26 15:55:03 -0700594 break;
595 }
596
David Howells6db3ac32017-03-16 16:27:44 +0000597 for (; req->index < req->nr_pages; req->index++) {
598 if (call->count < PAGE_SIZE)
599 zero_user_segment(req->pages[req->index],
600 call->count, PAGE_SIZE);
David Howells196ee9c2017-01-05 10:38:34 +0000601 if (req->page_done)
602 req->page_done(call, req);
David Howells6db3ac32017-03-16 16:27:44 +0000603 call->count = 0;
David Howells416351f2007-05-09 02:33:45 -0700604 }
605
David Howells08e0e7c2007-04-26 15:55:03 -0700606 _leave(" = 0 [done]");
607 return 0;
608}
609
David Howells196ee9c2017-01-05 10:38:34 +0000610static void afs_fetch_data_destructor(struct afs_call *call)
611{
David Howells97e30432017-11-02 15:27:48 +0000612 struct afs_read *req = call->reply[2];
David Howells196ee9c2017-01-05 10:38:34 +0000613
614 afs_put_read(req);
615 afs_flat_call_destructor(call);
616}
617
David Howells08e0e7c2007-04-26 15:55:03 -0700618/*
619 * FS.FetchData operation type
620 */
621static const struct afs_call_type afs_RXFSFetchData = {
David Howells00d3b7a2007-04-26 15:57:07 -0700622 .name = "FS.FetchData",
David Howells025db802017-11-02 15:27:51 +0000623 .op = afs_FS_FetchData,
David Howells08e0e7c2007-04-26 15:55:03 -0700624 .deliver = afs_deliver_fs_fetch_data,
David Howells196ee9c2017-01-05 10:38:34 +0000625 .destructor = afs_fetch_data_destructor,
David Howells08e0e7c2007-04-26 15:55:03 -0700626};
627
David Howellsb9b1f8d2007-05-10 03:15:21 -0700628static const struct afs_call_type afs_RXFSFetchData64 = {
629 .name = "FS.FetchData64",
David Howells025db802017-11-02 15:27:51 +0000630 .op = afs_FS_FetchData64,
David Howellsb9b1f8d2007-05-10 03:15:21 -0700631 .deliver = afs_deliver_fs_fetch_data,
David Howells196ee9c2017-01-05 10:38:34 +0000632 .destructor = afs_fetch_data_destructor,
David Howellsb9b1f8d2007-05-10 03:15:21 -0700633};
634
635/*
636 * fetch data from a very large file
637 */
David Howellsd2ddc772017-11-02 15:27:50 +0000638static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
David Howellsb9b1f8d2007-05-10 03:15:21 -0700639{
David Howellsd2ddc772017-11-02 15:27:50 +0000640 struct afs_vnode *vnode = fc->vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700641 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000642 struct afs_net *net = afs_v2net(vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700643 __be32 *bp;
644
645 _enter("");
646
David Howellsf044c882017-11-02 15:27:45 +0000647 call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700648 if (!call)
649 return -ENOMEM;
650
David Howellsd2ddc772017-11-02 15:27:50 +0000651 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000652 call->reply[0] = vnode;
653 call->reply[1] = NULL; /* volsync */
654 call->reply[2] = req;
David Howells0c3a5ac2018-04-06 14:17:24 +0100655 call->expected_version = vnode->status.data_version;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700656
657 /* marshall the parameters */
658 bp = call->request;
659 bp[0] = htonl(FSFETCHDATA64);
660 bp[1] = htonl(vnode->fid.vid);
661 bp[2] = htonl(vnode->fid.vnode);
662 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000663 bp[4] = htonl(upper_32_bits(req->pos));
664 bp[5] = htonl(lower_32_bits(req->pos));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700665 bp[6] = 0;
David Howells196ee9c2017-01-05 10:38:34 +0000666 bp[7] = htonl(lower_32_bits(req->len));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700667
David Howellsf3ddee82018-04-06 14:17:25 +0100668 refcount_inc(&req->usage);
David Howellsd2ddc772017-11-02 15:27:50 +0000669 call->cb_break = fc->cb_break;
670 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000671 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000672 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700673}
674
David Howells08e0e7c2007-04-26 15:55:03 -0700675/*
676 * fetch data from a file
677 */
David Howellsd2ddc772017-11-02 15:27:50 +0000678int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
David Howells08e0e7c2007-04-26 15:55:03 -0700679{
David Howellsd2ddc772017-11-02 15:27:50 +0000680 struct afs_vnode *vnode = fc->vnode;
David Howells08e0e7c2007-04-26 15:55:03 -0700681 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000682 struct afs_net *net = afs_v2net(vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 __be32 *bp;
684
David Howells196ee9c2017-01-05 10:38:34 +0000685 if (upper_32_bits(req->pos) ||
686 upper_32_bits(req->len) ||
687 upper_32_bits(req->pos + req->len))
David Howellsd2ddc772017-11-02 15:27:50 +0000688 return afs_fs_fetch_data64(fc, req);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700689
David Howells08e0e7c2007-04-26 15:55:03 -0700690 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
David Howellsf044c882017-11-02 15:27:45 +0000692 call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700693 if (!call)
694 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
David Howellsd2ddc772017-11-02 15:27:50 +0000696 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000697 call->reply[0] = vnode;
698 call->reply[1] = NULL; /* volsync */
699 call->reply[2] = req;
David Howells0c3a5ac2018-04-06 14:17:24 +0100700 call->expected_version = vnode->status.data_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700703 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 bp[0] = htonl(FSFETCHDATA);
David Howells08e0e7c2007-04-26 15:55:03 -0700705 bp[1] = htonl(vnode->fid.vid);
706 bp[2] = htonl(vnode->fid.vnode);
707 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000708 bp[4] = htonl(lower_32_bits(req->pos));
709 bp[5] = htonl(lower_32_bits(req->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
David Howellsf3ddee82018-04-06 14:17:25 +0100711 refcount_inc(&req->usage);
David Howellsd2ddc772017-11-02 15:27:50 +0000712 call->cb_break = fc->cb_break;
713 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000714 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000715 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsec268152007-04-26 15:49:28 -0700716}
David Howells260a9802007-04-26 15:59:35 -0700717
718/*
719 * deliver reply data to an FS.CreateFile or an FS.MakeDir
720 */
David Howellsd0016482016-08-30 20:42:14 +0100721static int afs_deliver_fs_create_vnode(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700722{
David Howells97e30432017-11-02 15:27:48 +0000723 struct afs_vnode *vnode = call->reply[0];
David Howells260a9802007-04-26 15:59:35 -0700724 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100725 int ret;
David Howells260a9802007-04-26 15:59:35 -0700726
David Howellsd0016482016-08-30 20:42:14 +0100727 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700728
David Howellsd0016482016-08-30 20:42:14 +0100729 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100730 if (ret < 0)
731 return ret;
David Howells260a9802007-04-26 15:59:35 -0700732
733 /* unmarshall the reply once we've received all of it */
734 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +0000735 xdr_decode_AFSFid(&bp, call->reply[1]);
David Howellsc875c762018-05-23 11:32:06 +0100736 if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 ||
737 afs_decode_status(call, &bp, &vnode->status, vnode,
738 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100739 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +0000740 xdr_decode_AFSCallBack_raw(&bp, call->reply[3]);
741 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700742
743 _leave(" = 0 [done]");
744 return 0;
745}
746
747/*
748 * FS.CreateFile and FS.MakeDir operation type
749 */
David Howells025db802017-11-02 15:27:51 +0000750static const struct afs_call_type afs_RXFSCreateFile = {
751 .name = "FS.CreateFile",
752 .op = afs_FS_CreateFile,
753 .deliver = afs_deliver_fs_create_vnode,
754 .destructor = afs_flat_call_destructor,
755};
756
757static const struct afs_call_type afs_RXFSMakeDir = {
758 .name = "FS.MakeDir",
759 .op = afs_FS_MakeDir,
David Howells260a9802007-04-26 15:59:35 -0700760 .deliver = afs_deliver_fs_create_vnode,
David Howells260a9802007-04-26 15:59:35 -0700761 .destructor = afs_flat_call_destructor,
762};
763
764/*
765 * create a file or make a directory
766 */
David Howells8b2a4642017-11-02 15:27:50 +0000767int afs_fs_create(struct afs_fs_cursor *fc,
David Howells260a9802007-04-26 15:59:35 -0700768 const char *name,
769 umode_t mode,
David Howells63a46812018-04-06 14:17:25 +0100770 u64 current_data_version,
David Howells260a9802007-04-26 15:59:35 -0700771 struct afs_fid *newfid,
772 struct afs_file_status *newstatus,
David Howellsd2ddc772017-11-02 15:27:50 +0000773 struct afs_callback *newcb)
David Howells260a9802007-04-26 15:59:35 -0700774{
David Howellsd2ddc772017-11-02 15:27:50 +0000775 struct afs_vnode *vnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700776 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000777 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700778 size_t namesz, reqsz, padsz;
779 __be32 *bp;
780
781 _enter("");
782
783 namesz = strlen(name);
784 padsz = (4 - (namesz & 3)) & 3;
785 reqsz = (5 * 4) + namesz + padsz + (6 * 4);
786
David Howells025db802017-11-02 15:27:51 +0000787 call = afs_alloc_flat_call(
788 net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile,
789 reqsz, (3 + 21 + 21 + 3 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -0700790 if (!call)
791 return -ENOMEM;
792
David Howellsd2ddc772017-11-02 15:27:50 +0000793 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000794 call->reply[0] = vnode;
795 call->reply[1] = newfid;
796 call->reply[2] = newstatus;
797 call->reply[3] = newcb;
David Howells63a46812018-04-06 14:17:25 +0100798 call->expected_version = current_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -0700799
800 /* marshall the parameters */
801 bp = call->request;
802 *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
803 *bp++ = htonl(vnode->fid.vid);
804 *bp++ = htonl(vnode->fid.vnode);
805 *bp++ = htonl(vnode->fid.unique);
806 *bp++ = htonl(namesz);
807 memcpy(bp, name, namesz);
808 bp = (void *) bp + namesz;
809 if (padsz > 0) {
810 memset(bp, 0, padsz);
811 bp = (void *) bp + padsz;
812 }
Marc Dionneab94f5d2017-03-16 16:27:47 +0000813 *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
814 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howells260a9802007-04-26 15:59:35 -0700815 *bp++ = 0; /* owner */
816 *bp++ = 0; /* group */
817 *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
818 *bp++ = 0; /* segment size */
819
David Howellsd2ddc772017-11-02 15:27:50 +0000820 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000821 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000822 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700823}
824
825/*
826 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
827 */
David Howellsd0016482016-08-30 20:42:14 +0100828static int afs_deliver_fs_remove(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700829{
David Howells97e30432017-11-02 15:27:48 +0000830 struct afs_vnode *vnode = call->reply[0];
David Howells260a9802007-04-26 15:59:35 -0700831 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100832 int ret;
David Howells260a9802007-04-26 15:59:35 -0700833
David Howellsd0016482016-08-30 20:42:14 +0100834 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700835
David Howellsd0016482016-08-30 20:42:14 +0100836 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100837 if (ret < 0)
838 return ret;
David Howells260a9802007-04-26 15:59:35 -0700839
840 /* unmarshall the reply once we've received all of it */
841 bp = call->buffer;
David Howellsc875c762018-05-23 11:32:06 +0100842 if (afs_decode_status(call, &bp, &vnode->status, vnode,
843 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100844 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +0000845 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700846
847 _leave(" = 0 [done]");
848 return 0;
849}
850
851/*
852 * FS.RemoveDir/FS.RemoveFile operation type
853 */
David Howells025db802017-11-02 15:27:51 +0000854static const struct afs_call_type afs_RXFSRemoveFile = {
855 .name = "FS.RemoveFile",
856 .op = afs_FS_RemoveFile,
857 .deliver = afs_deliver_fs_remove,
858 .destructor = afs_flat_call_destructor,
859};
860
861static const struct afs_call_type afs_RXFSRemoveDir = {
862 .name = "FS.RemoveDir",
863 .op = afs_FS_RemoveDir,
David Howells260a9802007-04-26 15:59:35 -0700864 .deliver = afs_deliver_fs_remove,
David Howells260a9802007-04-26 15:59:35 -0700865 .destructor = afs_flat_call_destructor,
866};
867
868/*
869 * remove a file or directory
870 */
David Howells63a46812018-04-06 14:17:25 +0100871int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir,
872 u64 current_data_version)
David Howells260a9802007-04-26 15:59:35 -0700873{
David Howellsd2ddc772017-11-02 15:27:50 +0000874 struct afs_vnode *vnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700875 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000876 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700877 size_t namesz, reqsz, padsz;
878 __be32 *bp;
879
880 _enter("");
881
882 namesz = strlen(name);
883 padsz = (4 - (namesz & 3)) & 3;
884 reqsz = (5 * 4) + namesz + padsz;
885
David Howells025db802017-11-02 15:27:51 +0000886 call = afs_alloc_flat_call(
887 net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile,
888 reqsz, (21 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -0700889 if (!call)
890 return -ENOMEM;
891
David Howellsd2ddc772017-11-02 15:27:50 +0000892 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000893 call->reply[0] = vnode;
David Howells63a46812018-04-06 14:17:25 +0100894 call->expected_version = current_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -0700895
896 /* marshall the parameters */
897 bp = call->request;
898 *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
899 *bp++ = htonl(vnode->fid.vid);
900 *bp++ = htonl(vnode->fid.vnode);
901 *bp++ = htonl(vnode->fid.unique);
902 *bp++ = htonl(namesz);
903 memcpy(bp, name, namesz);
904 bp = (void *) bp + namesz;
905 if (padsz > 0) {
906 memset(bp, 0, padsz);
907 bp = (void *) bp + padsz;
908 }
909
David Howellsd2ddc772017-11-02 15:27:50 +0000910 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000911 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000912 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700913}
914
915/*
916 * deliver reply data to an FS.Link
917 */
David Howellsd0016482016-08-30 20:42:14 +0100918static int afs_deliver_fs_link(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700919{
David Howells97e30432017-11-02 15:27:48 +0000920 struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1];
David Howells260a9802007-04-26 15:59:35 -0700921 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100922 int ret;
David Howells260a9802007-04-26 15:59:35 -0700923
David Howellsd0016482016-08-30 20:42:14 +0100924 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700925
David Howellsd0016482016-08-30 20:42:14 +0100926 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100927 if (ret < 0)
928 return ret;
David Howells260a9802007-04-26 15:59:35 -0700929
930 /* unmarshall the reply once we've received all of it */
931 bp = call->buffer;
David Howellsc875c762018-05-23 11:32:06 +0100932 if (afs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 ||
933 afs_decode_status(call, &bp, &dvnode->status, dvnode,
934 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +0100935 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +0000936 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700937
938 _leave(" = 0 [done]");
939 return 0;
940}
941
942/*
943 * FS.Link operation type
944 */
945static const struct afs_call_type afs_RXFSLink = {
946 .name = "FS.Link",
David Howells025db802017-11-02 15:27:51 +0000947 .op = afs_FS_Link,
David Howells260a9802007-04-26 15:59:35 -0700948 .deliver = afs_deliver_fs_link,
David Howells260a9802007-04-26 15:59:35 -0700949 .destructor = afs_flat_call_destructor,
950};
951
952/*
953 * make a hard link
954 */
David Howellsd2ddc772017-11-02 15:27:50 +0000955int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
David Howells63a46812018-04-06 14:17:25 +0100956 const char *name, u64 current_data_version)
David Howells260a9802007-04-26 15:59:35 -0700957{
David Howellsd2ddc772017-11-02 15:27:50 +0000958 struct afs_vnode *dvnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700959 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000960 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700961 size_t namesz, reqsz, padsz;
962 __be32 *bp;
963
964 _enter("");
965
966 namesz = strlen(name);
967 padsz = (4 - (namesz & 3)) & 3;
968 reqsz = (5 * 4) + namesz + padsz + (3 * 4);
969
David Howellsf044c882017-11-02 15:27:45 +0000970 call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -0700971 if (!call)
972 return -ENOMEM;
973
David Howellsd2ddc772017-11-02 15:27:50 +0000974 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000975 call->reply[0] = dvnode;
976 call->reply[1] = vnode;
David Howells63a46812018-04-06 14:17:25 +0100977 call->expected_version = current_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -0700978
979 /* marshall the parameters */
980 bp = call->request;
981 *bp++ = htonl(FSLINK);
982 *bp++ = htonl(dvnode->fid.vid);
983 *bp++ = htonl(dvnode->fid.vnode);
984 *bp++ = htonl(dvnode->fid.unique);
985 *bp++ = htonl(namesz);
986 memcpy(bp, name, namesz);
987 bp = (void *) bp + namesz;
988 if (padsz > 0) {
989 memset(bp, 0, padsz);
990 bp = (void *) bp + padsz;
991 }
992 *bp++ = htonl(vnode->fid.vid);
993 *bp++ = htonl(vnode->fid.vnode);
994 *bp++ = htonl(vnode->fid.unique);
995
David Howellsd2ddc772017-11-02 15:27:50 +0000996 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +0000997 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +0000998 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700999}
1000
1001/*
1002 * deliver reply data to an FS.Symlink
1003 */
David Howellsd0016482016-08-30 20:42:14 +01001004static int afs_deliver_fs_symlink(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -07001005{
David Howells97e30432017-11-02 15:27:48 +00001006 struct afs_vnode *vnode = call->reply[0];
David Howells260a9802007-04-26 15:59:35 -07001007 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001008 int ret;
David Howells260a9802007-04-26 15:59:35 -07001009
David Howellsd0016482016-08-30 20:42:14 +01001010 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -07001011
David Howellsd0016482016-08-30 20:42:14 +01001012 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001013 if (ret < 0)
1014 return ret;
David Howells260a9802007-04-26 15:59:35 -07001015
1016 /* unmarshall the reply once we've received all of it */
1017 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +00001018 xdr_decode_AFSFid(&bp, call->reply[1]);
David Howellsc875c762018-05-23 11:32:06 +01001019 if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) ||
1020 afs_decode_status(call, &bp, &vnode->status, vnode,
1021 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01001022 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +00001023 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -07001024
1025 _leave(" = 0 [done]");
1026 return 0;
1027}
1028
1029/*
1030 * FS.Symlink operation type
1031 */
1032static const struct afs_call_type afs_RXFSSymlink = {
1033 .name = "FS.Symlink",
David Howells025db802017-11-02 15:27:51 +00001034 .op = afs_FS_Symlink,
David Howells260a9802007-04-26 15:59:35 -07001035 .deliver = afs_deliver_fs_symlink,
David Howells260a9802007-04-26 15:59:35 -07001036 .destructor = afs_flat_call_destructor,
1037};
1038
1039/*
1040 * create a symbolic link
1041 */
David Howells8b2a4642017-11-02 15:27:50 +00001042int afs_fs_symlink(struct afs_fs_cursor *fc,
David Howells260a9802007-04-26 15:59:35 -07001043 const char *name,
1044 const char *contents,
David Howells63a46812018-04-06 14:17:25 +01001045 u64 current_data_version,
David Howells260a9802007-04-26 15:59:35 -07001046 struct afs_fid *newfid,
David Howellsd2ddc772017-11-02 15:27:50 +00001047 struct afs_file_status *newstatus)
David Howells260a9802007-04-26 15:59:35 -07001048{
David Howellsd2ddc772017-11-02 15:27:50 +00001049 struct afs_vnode *vnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -07001050 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001051 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -07001052 size_t namesz, reqsz, padsz, c_namesz, c_padsz;
1053 __be32 *bp;
1054
1055 _enter("");
1056
1057 namesz = strlen(name);
1058 padsz = (4 - (namesz & 3)) & 3;
1059
1060 c_namesz = strlen(contents);
1061 c_padsz = (4 - (c_namesz & 3)) & 3;
1062
1063 reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
1064
David Howellsf044c882017-11-02 15:27:45 +00001065 call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
David Howells260a9802007-04-26 15:59:35 -07001066 (3 + 21 + 21 + 6) * 4);
1067 if (!call)
1068 return -ENOMEM;
1069
David Howellsd2ddc772017-11-02 15:27:50 +00001070 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001071 call->reply[0] = vnode;
1072 call->reply[1] = newfid;
1073 call->reply[2] = newstatus;
David Howells63a46812018-04-06 14:17:25 +01001074 call->expected_version = current_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -07001075
1076 /* marshall the parameters */
1077 bp = call->request;
1078 *bp++ = htonl(FSSYMLINK);
1079 *bp++ = htonl(vnode->fid.vid);
1080 *bp++ = htonl(vnode->fid.vnode);
1081 *bp++ = htonl(vnode->fid.unique);
1082 *bp++ = htonl(namesz);
1083 memcpy(bp, name, namesz);
1084 bp = (void *) bp + namesz;
1085 if (padsz > 0) {
1086 memset(bp, 0, padsz);
1087 bp = (void *) bp + padsz;
1088 }
1089 *bp++ = htonl(c_namesz);
1090 memcpy(bp, contents, c_namesz);
1091 bp = (void *) bp + c_namesz;
1092 if (c_padsz > 0) {
1093 memset(bp, 0, c_padsz);
1094 bp = (void *) bp + c_padsz;
1095 }
Marc Dionneab94f5d2017-03-16 16:27:47 +00001096 *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
1097 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howells260a9802007-04-26 15:59:35 -07001098 *bp++ = 0; /* owner */
1099 *bp++ = 0; /* group */
1100 *bp++ = htonl(S_IRWXUGO); /* unix mode */
1101 *bp++ = 0; /* segment size */
1102
David Howellsd2ddc772017-11-02 15:27:50 +00001103 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001104 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001105 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -07001106}
1107
1108/*
1109 * deliver reply data to an FS.Rename
1110 */
David Howellsd0016482016-08-30 20:42:14 +01001111static int afs_deliver_fs_rename(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -07001112{
David Howells97e30432017-11-02 15:27:48 +00001113 struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1];
David Howells260a9802007-04-26 15:59:35 -07001114 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001115 int ret;
David Howells260a9802007-04-26 15:59:35 -07001116
David Howellsd0016482016-08-30 20:42:14 +01001117 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -07001118
David Howellsd0016482016-08-30 20:42:14 +01001119 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001120 if (ret < 0)
1121 return ret;
David Howells260a9802007-04-26 15:59:35 -07001122
1123 /* unmarshall the reply once we've received all of it */
1124 bp = call->buffer;
David Howellsc875c762018-05-23 11:32:06 +01001125 if (afs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode,
1126 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01001127 return afs_protocol_error(call, -EBADMSG);
David Howellsdd9fbcb2018-04-06 14:17:24 +01001128 if (new_dvnode != orig_dvnode &&
David Howellsc875c762018-05-23 11:32:06 +01001129 afs_decode_status(call, &bp, &new_dvnode->status, new_dvnode,
1130 &call->expected_version_2, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01001131 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +00001132 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -07001133
1134 _leave(" = 0 [done]");
1135 return 0;
1136}
1137
1138/*
1139 * FS.Rename operation type
1140 */
1141static const struct afs_call_type afs_RXFSRename = {
1142 .name = "FS.Rename",
David Howells025db802017-11-02 15:27:51 +00001143 .op = afs_FS_Rename,
David Howells260a9802007-04-26 15:59:35 -07001144 .deliver = afs_deliver_fs_rename,
David Howells260a9802007-04-26 15:59:35 -07001145 .destructor = afs_flat_call_destructor,
1146};
1147
1148/*
1149 * create a symbolic link
1150 */
David Howells8b2a4642017-11-02 15:27:50 +00001151int afs_fs_rename(struct afs_fs_cursor *fc,
David Howells260a9802007-04-26 15:59:35 -07001152 const char *orig_name,
1153 struct afs_vnode *new_dvnode,
David Howells63a46812018-04-06 14:17:25 +01001154 const char *new_name,
1155 u64 current_orig_data_version,
1156 u64 current_new_data_version)
David Howells260a9802007-04-26 15:59:35 -07001157{
David Howellsd2ddc772017-11-02 15:27:50 +00001158 struct afs_vnode *orig_dvnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -07001159 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001160 struct afs_net *net = afs_v2net(orig_dvnode);
David Howells260a9802007-04-26 15:59:35 -07001161 size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1162 __be32 *bp;
1163
1164 _enter("");
1165
1166 o_namesz = strlen(orig_name);
1167 o_padsz = (4 - (o_namesz & 3)) & 3;
1168
1169 n_namesz = strlen(new_name);
1170 n_padsz = (4 - (n_namesz & 3)) & 3;
1171
1172 reqsz = (4 * 4) +
1173 4 + o_namesz + o_padsz +
1174 (3 * 4) +
1175 4 + n_namesz + n_padsz;
1176
David Howellsf044c882017-11-02 15:27:45 +00001177 call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -07001178 if (!call)
1179 return -ENOMEM;
1180
David Howellsd2ddc772017-11-02 15:27:50 +00001181 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001182 call->reply[0] = orig_dvnode;
1183 call->reply[1] = new_dvnode;
David Howells63a46812018-04-06 14:17:25 +01001184 call->expected_version = current_orig_data_version + 1;
1185 call->expected_version_2 = current_new_data_version + 1;
David Howells260a9802007-04-26 15:59:35 -07001186
1187 /* marshall the parameters */
1188 bp = call->request;
1189 *bp++ = htonl(FSRENAME);
1190 *bp++ = htonl(orig_dvnode->fid.vid);
1191 *bp++ = htonl(orig_dvnode->fid.vnode);
1192 *bp++ = htonl(orig_dvnode->fid.unique);
1193 *bp++ = htonl(o_namesz);
1194 memcpy(bp, orig_name, o_namesz);
1195 bp = (void *) bp + o_namesz;
1196 if (o_padsz > 0) {
1197 memset(bp, 0, o_padsz);
1198 bp = (void *) bp + o_padsz;
1199 }
1200
1201 *bp++ = htonl(new_dvnode->fid.vid);
1202 *bp++ = htonl(new_dvnode->fid.vnode);
1203 *bp++ = htonl(new_dvnode->fid.unique);
1204 *bp++ = htonl(n_namesz);
1205 memcpy(bp, new_name, n_namesz);
1206 bp = (void *) bp + n_namesz;
1207 if (n_padsz > 0) {
1208 memset(bp, 0, n_padsz);
1209 bp = (void *) bp + n_padsz;
1210 }
1211
David Howellsd2ddc772017-11-02 15:27:50 +00001212 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001213 trace_afs_make_fs_call(call, &orig_dvnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001214 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -07001215}
David Howells31143d52007-05-09 02:33:46 -07001216
1217/*
1218 * deliver reply data to an FS.StoreData
1219 */
David Howellsd0016482016-08-30 20:42:14 +01001220static int afs_deliver_fs_store_data(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001221{
David Howells97e30432017-11-02 15:27:48 +00001222 struct afs_vnode *vnode = call->reply[0];
David Howells31143d52007-05-09 02:33:46 -07001223 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001224 int ret;
David Howells31143d52007-05-09 02:33:46 -07001225
David Howellsd0016482016-08-30 20:42:14 +01001226 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001227
David Howellsd0016482016-08-30 20:42:14 +01001228 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001229 if (ret < 0)
1230 return ret;
David Howells31143d52007-05-09 02:33:46 -07001231
1232 /* unmarshall the reply once we've received all of it */
1233 bp = call->buffer;
David Howellsc875c762018-05-23 11:32:06 +01001234 if (afs_decode_status(call, &bp, &vnode->status, vnode,
1235 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01001236 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +00001237 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells31143d52007-05-09 02:33:46 -07001238
1239 afs_pages_written_back(vnode, call);
1240
1241 _leave(" = 0 [done]");
1242 return 0;
1243}
1244
1245/*
1246 * FS.StoreData operation type
1247 */
1248static const struct afs_call_type afs_RXFSStoreData = {
1249 .name = "FS.StoreData",
David Howells025db802017-11-02 15:27:51 +00001250 .op = afs_FS_StoreData,
David Howells31143d52007-05-09 02:33:46 -07001251 .deliver = afs_deliver_fs_store_data,
David Howells31143d52007-05-09 02:33:46 -07001252 .destructor = afs_flat_call_destructor,
1253};
1254
David Howellsb9b1f8d2007-05-10 03:15:21 -07001255static const struct afs_call_type afs_RXFSStoreData64 = {
1256 .name = "FS.StoreData64",
David Howells025db802017-11-02 15:27:51 +00001257 .op = afs_FS_StoreData64,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001258 .deliver = afs_deliver_fs_store_data,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001259 .destructor = afs_flat_call_destructor,
1260};
1261
1262/*
1263 * store a set of pages to a very large file
1264 */
David Howells8b2a4642017-11-02 15:27:50 +00001265static int afs_fs_store_data64(struct afs_fs_cursor *fc,
David Howells4343d002017-11-02 15:27:52 +00001266 struct address_space *mapping,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001267 pgoff_t first, pgoff_t last,
1268 unsigned offset, unsigned to,
David Howellsd2ddc772017-11-02 15:27:50 +00001269 loff_t size, loff_t pos, loff_t i_size)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001270{
David Howells4343d002017-11-02 15:27:52 +00001271 struct afs_vnode *vnode = fc->vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001272 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001273 struct afs_net *net = afs_v2net(vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001274 __be32 *bp;
1275
1276 _enter(",%x,{%x:%u},,",
David Howells4343d002017-11-02 15:27:52 +00001277 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001278
David Howellsf044c882017-11-02 15:27:45 +00001279 call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001280 (4 + 6 + 3 * 2) * 4,
1281 (21 + 6) * 4);
1282 if (!call)
1283 return -ENOMEM;
1284
David Howells4343d002017-11-02 15:27:52 +00001285 call->key = fc->key;
1286 call->mapping = mapping;
David Howells97e30432017-11-02 15:27:48 +00001287 call->reply[0] = vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001288 call->first = first;
1289 call->last = last;
1290 call->first_offset = offset;
1291 call->last_to = to;
1292 call->send_pages = true;
David Howells0c3a5ac2018-04-06 14:17:24 +01001293 call->expected_version = vnode->status.data_version + 1;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001294
1295 /* marshall the parameters */
1296 bp = call->request;
1297 *bp++ = htonl(FSSTOREDATA64);
1298 *bp++ = htonl(vnode->fid.vid);
1299 *bp++ = htonl(vnode->fid.vnode);
1300 *bp++ = htonl(vnode->fid.unique);
1301
Marc Dionneab94f5d2017-03-16 16:27:47 +00001302 *bp++ = htonl(AFS_SET_MTIME); /* mask */
1303 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howellsb9b1f8d2007-05-10 03:15:21 -07001304 *bp++ = 0; /* owner */
1305 *bp++ = 0; /* group */
1306 *bp++ = 0; /* unix mode */
1307 *bp++ = 0; /* segment size */
1308
1309 *bp++ = htonl(pos >> 32);
1310 *bp++ = htonl((u32) pos);
1311 *bp++ = htonl(size >> 32);
1312 *bp++ = htonl((u32) size);
1313 *bp++ = htonl(i_size >> 32);
1314 *bp++ = htonl((u32) i_size);
1315
David Howells025db802017-11-02 15:27:51 +00001316 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001317 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001318}
1319
David Howells31143d52007-05-09 02:33:46 -07001320/*
1321 * store a set of pages
1322 */
David Howells4343d002017-11-02 15:27:52 +00001323int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
David Howells31143d52007-05-09 02:33:46 -07001324 pgoff_t first, pgoff_t last,
David Howellsd2ddc772017-11-02 15:27:50 +00001325 unsigned offset, unsigned to)
David Howells31143d52007-05-09 02:33:46 -07001326{
David Howells4343d002017-11-02 15:27:52 +00001327 struct afs_vnode *vnode = fc->vnode;
David Howells31143d52007-05-09 02:33:46 -07001328 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001329 struct afs_net *net = afs_v2net(vnode);
David Howells31143d52007-05-09 02:33:46 -07001330 loff_t size, pos, i_size;
1331 __be32 *bp;
1332
1333 _enter(",%x,{%x:%u},,",
David Howells4343d002017-11-02 15:27:52 +00001334 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howells31143d52007-05-09 02:33:46 -07001335
David Howells146a1192017-03-16 16:27:47 +00001336 size = (loff_t)to - (loff_t)offset;
David Howells31143d52007-05-09 02:33:46 -07001337 if (first != last)
1338 size += (loff_t)(last - first) << PAGE_SHIFT;
1339 pos = (loff_t)first << PAGE_SHIFT;
1340 pos += offset;
1341
1342 i_size = i_size_read(&vnode->vfs_inode);
1343 if (pos + size > i_size)
1344 i_size = size + pos;
1345
1346 _debug("size %llx, at %llx, i_size %llx",
1347 (unsigned long long) size, (unsigned long long) pos,
1348 (unsigned long long) i_size);
1349
David Howellsb9b1f8d2007-05-10 03:15:21 -07001350 if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
David Howells4343d002017-11-02 15:27:52 +00001351 return afs_fs_store_data64(fc, mapping, first, last, offset, to,
David Howellsd2ddc772017-11-02 15:27:50 +00001352 size, pos, i_size);
David Howells31143d52007-05-09 02:33:46 -07001353
David Howellsf044c882017-11-02 15:27:45 +00001354 call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
David Howells31143d52007-05-09 02:33:46 -07001355 (4 + 6 + 3) * 4,
1356 (21 + 6) * 4);
1357 if (!call)
1358 return -ENOMEM;
1359
David Howells4343d002017-11-02 15:27:52 +00001360 call->key = fc->key;
1361 call->mapping = mapping;
David Howells97e30432017-11-02 15:27:48 +00001362 call->reply[0] = vnode;
David Howells31143d52007-05-09 02:33:46 -07001363 call->first = first;
1364 call->last = last;
1365 call->first_offset = offset;
1366 call->last_to = to;
1367 call->send_pages = true;
David Howells0c3a5ac2018-04-06 14:17:24 +01001368 call->expected_version = vnode->status.data_version + 1;
David Howells31143d52007-05-09 02:33:46 -07001369
1370 /* marshall the parameters */
1371 bp = call->request;
1372 *bp++ = htonl(FSSTOREDATA);
1373 *bp++ = htonl(vnode->fid.vid);
1374 *bp++ = htonl(vnode->fid.vnode);
1375 *bp++ = htonl(vnode->fid.unique);
1376
Marc Dionneab94f5d2017-03-16 16:27:47 +00001377 *bp++ = htonl(AFS_SET_MTIME); /* mask */
1378 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howells31143d52007-05-09 02:33:46 -07001379 *bp++ = 0; /* owner */
1380 *bp++ = 0; /* group */
1381 *bp++ = 0; /* unix mode */
1382 *bp++ = 0; /* segment size */
1383
1384 *bp++ = htonl(pos);
1385 *bp++ = htonl(size);
1386 *bp++ = htonl(i_size);
1387
David Howellsd2ddc772017-11-02 15:27:50 +00001388 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001389 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001390 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells31143d52007-05-09 02:33:46 -07001391}
1392
1393/*
1394 * deliver reply data to an FS.StoreStatus
1395 */
David Howellsd0016482016-08-30 20:42:14 +01001396static int afs_deliver_fs_store_status(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001397{
David Howells97e30432017-11-02 15:27:48 +00001398 struct afs_vnode *vnode = call->reply[0];
David Howells31143d52007-05-09 02:33:46 -07001399 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001400 int ret;
David Howells31143d52007-05-09 02:33:46 -07001401
David Howellsd0016482016-08-30 20:42:14 +01001402 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001403
David Howellsd0016482016-08-30 20:42:14 +01001404 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001405 if (ret < 0)
1406 return ret;
David Howells31143d52007-05-09 02:33:46 -07001407
1408 /* unmarshall the reply once we've received all of it */
David Howells31143d52007-05-09 02:33:46 -07001409 bp = call->buffer;
David Howellsc875c762018-05-23 11:32:06 +01001410 if (afs_decode_status(call, &bp, &vnode->status, vnode,
1411 &call->expected_version, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01001412 return afs_protocol_error(call, -EBADMSG);
David Howells97e30432017-11-02 15:27:48 +00001413 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells31143d52007-05-09 02:33:46 -07001414
1415 _leave(" = 0 [done]");
1416 return 0;
1417}
1418
1419/*
1420 * FS.StoreStatus operation type
1421 */
1422static const struct afs_call_type afs_RXFSStoreStatus = {
1423 .name = "FS.StoreStatus",
David Howells025db802017-11-02 15:27:51 +00001424 .op = afs_FS_StoreStatus,
David Howells31143d52007-05-09 02:33:46 -07001425 .deliver = afs_deliver_fs_store_status,
David Howells31143d52007-05-09 02:33:46 -07001426 .destructor = afs_flat_call_destructor,
1427};
1428
1429static const struct afs_call_type afs_RXFSStoreData_as_Status = {
1430 .name = "FS.StoreData",
David Howells025db802017-11-02 15:27:51 +00001431 .op = afs_FS_StoreData,
David Howells31143d52007-05-09 02:33:46 -07001432 .deliver = afs_deliver_fs_store_status,
David Howells31143d52007-05-09 02:33:46 -07001433 .destructor = afs_flat_call_destructor,
1434};
1435
David Howellsb9b1f8d2007-05-10 03:15:21 -07001436static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1437 .name = "FS.StoreData64",
David Howells025db802017-11-02 15:27:51 +00001438 .op = afs_FS_StoreData64,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001439 .deliver = afs_deliver_fs_store_status,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001440 .destructor = afs_flat_call_destructor,
1441};
1442
1443/*
1444 * set the attributes on a very large file, using FS.StoreData rather than
1445 * FS.StoreStatus so as to alter the file size also
1446 */
David Howellsd2ddc772017-11-02 15:27:50 +00001447static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001448{
David Howellsd2ddc772017-11-02 15:27:50 +00001449 struct afs_vnode *vnode = fc->vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001450 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001451 struct afs_net *net = afs_v2net(vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001452 __be32 *bp;
1453
1454 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +00001455 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001456
1457 ASSERT(attr->ia_valid & ATTR_SIZE);
1458
David Howellsf044c882017-11-02 15:27:45 +00001459 call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001460 (4 + 6 + 3 * 2) * 4,
1461 (21 + 6) * 4);
1462 if (!call)
1463 return -ENOMEM;
1464
David Howellsd2ddc772017-11-02 15:27:50 +00001465 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001466 call->reply[0] = vnode;
David Howells0c3a5ac2018-04-06 14:17:24 +01001467 call->expected_version = vnode->status.data_version + 1;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001468
1469 /* marshall the parameters */
1470 bp = call->request;
1471 *bp++ = htonl(FSSTOREDATA64);
1472 *bp++ = htonl(vnode->fid.vid);
1473 *bp++ = htonl(vnode->fid.vnode);
1474 *bp++ = htonl(vnode->fid.unique);
1475
1476 xdr_encode_AFS_StoreStatus(&bp, attr);
1477
1478 *bp++ = 0; /* position of start of write */
1479 *bp++ = 0;
1480 *bp++ = 0; /* size of write */
1481 *bp++ = 0;
1482 *bp++ = htonl(attr->ia_size >> 32); /* new file length */
1483 *bp++ = htonl((u32) attr->ia_size);
1484
David Howellsd2ddc772017-11-02 15:27:50 +00001485 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001486 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001487 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001488}
1489
David Howells31143d52007-05-09 02:33:46 -07001490/*
1491 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
1492 * so as to alter the file size also
1493 */
David Howellsd2ddc772017-11-02 15:27:50 +00001494static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
David Howells31143d52007-05-09 02:33:46 -07001495{
David Howellsd2ddc772017-11-02 15:27:50 +00001496 struct afs_vnode *vnode = fc->vnode;
David Howells31143d52007-05-09 02:33:46 -07001497 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001498 struct afs_net *net = afs_v2net(vnode);
David Howells31143d52007-05-09 02:33:46 -07001499 __be32 *bp;
1500
1501 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +00001502 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howells31143d52007-05-09 02:33:46 -07001503
1504 ASSERT(attr->ia_valid & ATTR_SIZE);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001505 if (attr->ia_size >> 32)
David Howellsd2ddc772017-11-02 15:27:50 +00001506 return afs_fs_setattr_size64(fc, attr);
David Howells31143d52007-05-09 02:33:46 -07001507
David Howellsf044c882017-11-02 15:27:45 +00001508 call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
David Howells31143d52007-05-09 02:33:46 -07001509 (4 + 6 + 3) * 4,
1510 (21 + 6) * 4);
1511 if (!call)
1512 return -ENOMEM;
1513
David Howellsd2ddc772017-11-02 15:27:50 +00001514 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001515 call->reply[0] = vnode;
David Howells0c3a5ac2018-04-06 14:17:24 +01001516 call->expected_version = vnode->status.data_version + 1;
David Howells31143d52007-05-09 02:33:46 -07001517
1518 /* marshall the parameters */
1519 bp = call->request;
1520 *bp++ = htonl(FSSTOREDATA);
1521 *bp++ = htonl(vnode->fid.vid);
1522 *bp++ = htonl(vnode->fid.vnode);
1523 *bp++ = htonl(vnode->fid.unique);
1524
1525 xdr_encode_AFS_StoreStatus(&bp, attr);
1526
1527 *bp++ = 0; /* position of start of write */
1528 *bp++ = 0; /* size of write */
1529 *bp++ = htonl(attr->ia_size); /* new file length */
1530
David Howellsd2ddc772017-11-02 15:27:50 +00001531 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001532 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001533 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells31143d52007-05-09 02:33:46 -07001534}
1535
1536/*
1537 * set the attributes on a file, using FS.StoreData if there's a change in file
1538 * size, and FS.StoreStatus otherwise
1539 */
David Howellsd2ddc772017-11-02 15:27:50 +00001540int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
David Howells31143d52007-05-09 02:33:46 -07001541{
David Howellsd2ddc772017-11-02 15:27:50 +00001542 struct afs_vnode *vnode = fc->vnode;
David Howells31143d52007-05-09 02:33:46 -07001543 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001544 struct afs_net *net = afs_v2net(vnode);
David Howells31143d52007-05-09 02:33:46 -07001545 __be32 *bp;
1546
1547 if (attr->ia_valid & ATTR_SIZE)
David Howellsd2ddc772017-11-02 15:27:50 +00001548 return afs_fs_setattr_size(fc, attr);
David Howells31143d52007-05-09 02:33:46 -07001549
1550 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +00001551 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howells31143d52007-05-09 02:33:46 -07001552
David Howellsf044c882017-11-02 15:27:45 +00001553 call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
David Howells31143d52007-05-09 02:33:46 -07001554 (4 + 6) * 4,
1555 (21 + 6) * 4);
1556 if (!call)
1557 return -ENOMEM;
1558
David Howellsd2ddc772017-11-02 15:27:50 +00001559 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001560 call->reply[0] = vnode;
David Howells0c3a5ac2018-04-06 14:17:24 +01001561 call->expected_version = vnode->status.data_version;
David Howells31143d52007-05-09 02:33:46 -07001562
1563 /* marshall the parameters */
1564 bp = call->request;
1565 *bp++ = htonl(FSSTORESTATUS);
1566 *bp++ = htonl(vnode->fid.vid);
1567 *bp++ = htonl(vnode->fid.vnode);
1568 *bp++ = htonl(vnode->fid.unique);
1569
1570 xdr_encode_AFS_StoreStatus(&bp, attr);
1571
David Howellsd2ddc772017-11-02 15:27:50 +00001572 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001573 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001574 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells31143d52007-05-09 02:33:46 -07001575}
David Howells45222b92007-05-10 22:22:20 -07001576
1577/*
1578 * deliver reply data to an FS.GetVolumeStatus
1579 */
David Howellsd0016482016-08-30 20:42:14 +01001580static int afs_deliver_fs_get_volume_status(struct afs_call *call)
David Howells45222b92007-05-10 22:22:20 -07001581{
1582 const __be32 *bp;
1583 char *p;
1584 int ret;
1585
David Howellsd0016482016-08-30 20:42:14 +01001586 _enter("{%u}", call->unmarshall);
David Howells45222b92007-05-10 22:22:20 -07001587
1588 switch (call->unmarshall) {
1589 case 0:
1590 call->offset = 0;
1591 call->unmarshall++;
1592
1593 /* extract the returned status record */
1594 case 1:
1595 _debug("extract status");
David Howellsd0016482016-08-30 20:42:14 +01001596 ret = afs_extract_data(call, call->buffer,
1597 12 * 4, true);
David Howells372ee162016-08-03 14:11:40 +01001598 if (ret < 0)
1599 return ret;
David Howells45222b92007-05-10 22:22:20 -07001600
1601 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +00001602 xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]);
David Howells45222b92007-05-10 22:22:20 -07001603 call->offset = 0;
1604 call->unmarshall++;
1605
1606 /* extract the volume name length */
1607 case 2:
David Howellsd0016482016-08-30 20:42:14 +01001608 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001609 if (ret < 0)
1610 return ret;
David Howells45222b92007-05-10 22:22:20 -07001611
1612 call->count = ntohl(call->tmp);
1613 _debug("volname length: %u", call->count);
1614 if (call->count >= AFSNAMEMAX)
David Howells5f702c82018-04-06 14:17:25 +01001615 return afs_protocol_error(call, -EBADMSG);
David Howells45222b92007-05-10 22:22:20 -07001616 call->offset = 0;
1617 call->unmarshall++;
1618
1619 /* extract the volume name */
1620 case 3:
1621 _debug("extract volname");
1622 if (call->count > 0) {
David Howells97e30432017-11-02 15:27:48 +00001623 ret = afs_extract_data(call, call->reply[2],
David Howellsd0016482016-08-30 20:42:14 +01001624 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001625 if (ret < 0)
1626 return ret;
David Howells45222b92007-05-10 22:22:20 -07001627 }
1628
David Howells97e30432017-11-02 15:27:48 +00001629 p = call->reply[2];
David Howells45222b92007-05-10 22:22:20 -07001630 p[call->count] = 0;
1631 _debug("volname '%s'", p);
1632
1633 call->offset = 0;
1634 call->unmarshall++;
1635
1636 /* extract the volume name padding */
1637 if ((call->count & 3) == 0) {
1638 call->unmarshall++;
1639 goto no_volname_padding;
1640 }
1641 call->count = 4 - (call->count & 3);
1642
1643 case 4:
David Howellsd0016482016-08-30 20:42:14 +01001644 ret = afs_extract_data(call, call->buffer,
1645 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001646 if (ret < 0)
1647 return ret;
David Howells45222b92007-05-10 22:22:20 -07001648
1649 call->offset = 0;
1650 call->unmarshall++;
1651 no_volname_padding:
1652
1653 /* extract the offline message length */
1654 case 5:
David Howellsd0016482016-08-30 20:42:14 +01001655 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001656 if (ret < 0)
1657 return ret;
David Howells45222b92007-05-10 22:22:20 -07001658
1659 call->count = ntohl(call->tmp);
1660 _debug("offline msg length: %u", call->count);
1661 if (call->count >= AFSNAMEMAX)
David Howells5f702c82018-04-06 14:17:25 +01001662 return afs_protocol_error(call, -EBADMSG);
David Howells45222b92007-05-10 22:22:20 -07001663 call->offset = 0;
1664 call->unmarshall++;
1665
1666 /* extract the offline message */
1667 case 6:
1668 _debug("extract offline");
1669 if (call->count > 0) {
David Howells97e30432017-11-02 15:27:48 +00001670 ret = afs_extract_data(call, call->reply[2],
David Howellsd0016482016-08-30 20:42:14 +01001671 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001672 if (ret < 0)
1673 return ret;
David Howells45222b92007-05-10 22:22:20 -07001674 }
1675
David Howells97e30432017-11-02 15:27:48 +00001676 p = call->reply[2];
David Howells45222b92007-05-10 22:22:20 -07001677 p[call->count] = 0;
1678 _debug("offline '%s'", p);
1679
1680 call->offset = 0;
1681 call->unmarshall++;
1682
1683 /* extract the offline message padding */
1684 if ((call->count & 3) == 0) {
1685 call->unmarshall++;
1686 goto no_offline_padding;
1687 }
1688 call->count = 4 - (call->count & 3);
1689
1690 case 7:
David Howellsd0016482016-08-30 20:42:14 +01001691 ret = afs_extract_data(call, call->buffer,
1692 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001693 if (ret < 0)
1694 return ret;
David Howells45222b92007-05-10 22:22:20 -07001695
1696 call->offset = 0;
1697 call->unmarshall++;
1698 no_offline_padding:
1699
1700 /* extract the message of the day length */
1701 case 8:
David Howellsd0016482016-08-30 20:42:14 +01001702 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001703 if (ret < 0)
1704 return ret;
David Howells45222b92007-05-10 22:22:20 -07001705
1706 call->count = ntohl(call->tmp);
1707 _debug("motd length: %u", call->count);
1708 if (call->count >= AFSNAMEMAX)
David Howells5f702c82018-04-06 14:17:25 +01001709 return afs_protocol_error(call, -EBADMSG);
David Howells45222b92007-05-10 22:22:20 -07001710 call->offset = 0;
1711 call->unmarshall++;
1712
1713 /* extract the message of the day */
1714 case 9:
1715 _debug("extract motd");
1716 if (call->count > 0) {
David Howells97e30432017-11-02 15:27:48 +00001717 ret = afs_extract_data(call, call->reply[2],
David Howellsd0016482016-08-30 20:42:14 +01001718 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001719 if (ret < 0)
1720 return ret;
David Howells45222b92007-05-10 22:22:20 -07001721 }
1722
David Howells97e30432017-11-02 15:27:48 +00001723 p = call->reply[2];
David Howells45222b92007-05-10 22:22:20 -07001724 p[call->count] = 0;
1725 _debug("motd '%s'", p);
1726
1727 call->offset = 0;
1728 call->unmarshall++;
1729
1730 /* extract the message of the day padding */
David Howellsd0016482016-08-30 20:42:14 +01001731 call->count = (4 - (call->count & 3)) & 3;
David Howells45222b92007-05-10 22:22:20 -07001732
1733 case 10:
David Howellsd0016482016-08-30 20:42:14 +01001734 ret = afs_extract_data(call, call->buffer,
1735 call->count, false);
David Howells372ee162016-08-03 14:11:40 +01001736 if (ret < 0)
1737 return ret;
David Howells45222b92007-05-10 22:22:20 -07001738
1739 call->offset = 0;
1740 call->unmarshall++;
David Howells45222b92007-05-10 22:22:20 -07001741 case 11:
David Howells45222b92007-05-10 22:22:20 -07001742 break;
1743 }
1744
David Howells45222b92007-05-10 22:22:20 -07001745 _leave(" = 0 [done]");
1746 return 0;
1747}
1748
1749/*
1750 * destroy an FS.GetVolumeStatus call
1751 */
1752static void afs_get_volume_status_call_destructor(struct afs_call *call)
1753{
David Howells97e30432017-11-02 15:27:48 +00001754 kfree(call->reply[2]);
1755 call->reply[2] = NULL;
David Howells45222b92007-05-10 22:22:20 -07001756 afs_flat_call_destructor(call);
1757}
1758
1759/*
1760 * FS.GetVolumeStatus operation type
1761 */
1762static const struct afs_call_type afs_RXFSGetVolumeStatus = {
1763 .name = "FS.GetVolumeStatus",
David Howells025db802017-11-02 15:27:51 +00001764 .op = afs_FS_GetVolumeStatus,
David Howells45222b92007-05-10 22:22:20 -07001765 .deliver = afs_deliver_fs_get_volume_status,
David Howells45222b92007-05-10 22:22:20 -07001766 .destructor = afs_get_volume_status_call_destructor,
1767};
1768
1769/*
1770 * fetch the status of a volume
1771 */
David Howells8b2a4642017-11-02 15:27:50 +00001772int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
David Howellsd2ddc772017-11-02 15:27:50 +00001773 struct afs_volume_status *vs)
David Howells45222b92007-05-10 22:22:20 -07001774{
David Howellsd2ddc772017-11-02 15:27:50 +00001775 struct afs_vnode *vnode = fc->vnode;
David Howells45222b92007-05-10 22:22:20 -07001776 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001777 struct afs_net *net = afs_v2net(vnode);
David Howells45222b92007-05-10 22:22:20 -07001778 __be32 *bp;
1779 void *tmpbuf;
1780
1781 _enter("");
1782
1783 tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
1784 if (!tmpbuf)
1785 return -ENOMEM;
1786
David Howellsf044c882017-11-02 15:27:45 +00001787 call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
David Howells45222b92007-05-10 22:22:20 -07001788 if (!call) {
1789 kfree(tmpbuf);
1790 return -ENOMEM;
1791 }
1792
David Howellsd2ddc772017-11-02 15:27:50 +00001793 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001794 call->reply[0] = vnode;
1795 call->reply[1] = vs;
1796 call->reply[2] = tmpbuf;
David Howells45222b92007-05-10 22:22:20 -07001797
1798 /* marshall the parameters */
1799 bp = call->request;
1800 bp[0] = htonl(FSGETVOLUMESTATUS);
1801 bp[1] = htonl(vnode->fid.vid);
1802
David Howellsd2ddc772017-11-02 15:27:50 +00001803 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001804 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001805 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells45222b92007-05-10 22:22:20 -07001806}
David Howellse8d6c552007-07-15 23:40:12 -07001807
1808/*
1809 * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1810 */
David Howellsd0016482016-08-30 20:42:14 +01001811static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
David Howellse8d6c552007-07-15 23:40:12 -07001812{
1813 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001814 int ret;
David Howellse8d6c552007-07-15 23:40:12 -07001815
David Howellsd0016482016-08-30 20:42:14 +01001816 _enter("{%u}", call->unmarshall);
David Howellse8d6c552007-07-15 23:40:12 -07001817
David Howellsd0016482016-08-30 20:42:14 +01001818 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001819 if (ret < 0)
1820 return ret;
David Howellse8d6c552007-07-15 23:40:12 -07001821
1822 /* unmarshall the reply once we've received all of it */
1823 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +00001824 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howellse8d6c552007-07-15 23:40:12 -07001825
1826 _leave(" = 0 [done]");
1827 return 0;
1828}
1829
1830/*
1831 * FS.SetLock operation type
1832 */
1833static const struct afs_call_type afs_RXFSSetLock = {
1834 .name = "FS.SetLock",
David Howells025db802017-11-02 15:27:51 +00001835 .op = afs_FS_SetLock,
David Howellse8d6c552007-07-15 23:40:12 -07001836 .deliver = afs_deliver_fs_xxxx_lock,
David Howellse8d6c552007-07-15 23:40:12 -07001837 .destructor = afs_flat_call_destructor,
1838};
1839
1840/*
1841 * FS.ExtendLock operation type
1842 */
1843static const struct afs_call_type afs_RXFSExtendLock = {
1844 .name = "FS.ExtendLock",
David Howells025db802017-11-02 15:27:51 +00001845 .op = afs_FS_ExtendLock,
David Howellse8d6c552007-07-15 23:40:12 -07001846 .deliver = afs_deliver_fs_xxxx_lock,
David Howellse8d6c552007-07-15 23:40:12 -07001847 .destructor = afs_flat_call_destructor,
1848};
1849
1850/*
1851 * FS.ReleaseLock operation type
1852 */
1853static const struct afs_call_type afs_RXFSReleaseLock = {
1854 .name = "FS.ReleaseLock",
David Howells025db802017-11-02 15:27:51 +00001855 .op = afs_FS_ReleaseLock,
David Howellse8d6c552007-07-15 23:40:12 -07001856 .deliver = afs_deliver_fs_xxxx_lock,
David Howellse8d6c552007-07-15 23:40:12 -07001857 .destructor = afs_flat_call_destructor,
1858};
1859
1860/*
David Howellsd2ddc772017-11-02 15:27:50 +00001861 * Set a lock on a file
David Howellse8d6c552007-07-15 23:40:12 -07001862 */
David Howellsd2ddc772017-11-02 15:27:50 +00001863int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
David Howellse8d6c552007-07-15 23:40:12 -07001864{
David Howellsd2ddc772017-11-02 15:27:50 +00001865 struct afs_vnode *vnode = fc->vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001866 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001867 struct afs_net *net = afs_v2net(vnode);
David Howellse8d6c552007-07-15 23:40:12 -07001868 __be32 *bp;
1869
1870 _enter("");
1871
David Howellsf044c882017-11-02 15:27:45 +00001872 call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
David Howellse8d6c552007-07-15 23:40:12 -07001873 if (!call)
1874 return -ENOMEM;
1875
David Howellsd2ddc772017-11-02 15:27:50 +00001876 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001877 call->reply[0] = vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001878
1879 /* marshall the parameters */
1880 bp = call->request;
1881 *bp++ = htonl(FSSETLOCK);
1882 *bp++ = htonl(vnode->fid.vid);
1883 *bp++ = htonl(vnode->fid.vnode);
1884 *bp++ = htonl(vnode->fid.unique);
1885 *bp++ = htonl(type);
1886
David Howellsd2ddc772017-11-02 15:27:50 +00001887 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001888 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001889 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellse8d6c552007-07-15 23:40:12 -07001890}
1891
1892/*
1893 * extend a lock on a file
1894 */
David Howellsd2ddc772017-11-02 15:27:50 +00001895int afs_fs_extend_lock(struct afs_fs_cursor *fc)
David Howellse8d6c552007-07-15 23:40:12 -07001896{
David Howellsd2ddc772017-11-02 15:27:50 +00001897 struct afs_vnode *vnode = fc->vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001898 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001899 struct afs_net *net = afs_v2net(vnode);
David Howellse8d6c552007-07-15 23:40:12 -07001900 __be32 *bp;
1901
1902 _enter("");
1903
David Howellsf044c882017-11-02 15:27:45 +00001904 call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
David Howellse8d6c552007-07-15 23:40:12 -07001905 if (!call)
1906 return -ENOMEM;
1907
David Howellsd2ddc772017-11-02 15:27:50 +00001908 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001909 call->reply[0] = vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001910
1911 /* marshall the parameters */
1912 bp = call->request;
1913 *bp++ = htonl(FSEXTENDLOCK);
1914 *bp++ = htonl(vnode->fid.vid);
1915 *bp++ = htonl(vnode->fid.vnode);
1916 *bp++ = htonl(vnode->fid.unique);
1917
David Howellsd2ddc772017-11-02 15:27:50 +00001918 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001919 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001920 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellse8d6c552007-07-15 23:40:12 -07001921}
1922
1923/*
1924 * release a lock on a file
1925 */
David Howellsd2ddc772017-11-02 15:27:50 +00001926int afs_fs_release_lock(struct afs_fs_cursor *fc)
David Howellse8d6c552007-07-15 23:40:12 -07001927{
David Howellsd2ddc772017-11-02 15:27:50 +00001928 struct afs_vnode *vnode = fc->vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001929 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001930 struct afs_net *net = afs_v2net(vnode);
David Howellse8d6c552007-07-15 23:40:12 -07001931 __be32 *bp;
1932
1933 _enter("");
1934
David Howellsf044c882017-11-02 15:27:45 +00001935 call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
David Howellse8d6c552007-07-15 23:40:12 -07001936 if (!call)
1937 return -ENOMEM;
1938
David Howellsd2ddc772017-11-02 15:27:50 +00001939 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001940 call->reply[0] = vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001941
1942 /* marshall the parameters */
1943 bp = call->request;
1944 *bp++ = htonl(FSRELEASELOCK);
1945 *bp++ = htonl(vnode->fid.vid);
1946 *bp++ = htonl(vnode->fid.vnode);
1947 *bp++ = htonl(vnode->fid.unique);
1948
David Howellsd2ddc772017-11-02 15:27:50 +00001949 afs_use_fs_server(call, fc->cbi);
David Howells025db802017-11-02 15:27:51 +00001950 trace_afs_make_fs_call(call, &vnode->fid);
David Howellsd2ddc772017-11-02 15:27:50 +00001951 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsc435ee32017-11-02 15:27:49 +00001952}
1953
1954/*
1955 * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1956 */
1957static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1958{
1959 return afs_transfer_reply(call);
1960}
1961
1962/*
1963 * FS.GiveUpAllCallBacks operation type
1964 */
1965static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1966 .name = "FS.GiveUpAllCallBacks",
David Howells025db802017-11-02 15:27:51 +00001967 .op = afs_FS_GiveUpAllCallBacks,
David Howellsc435ee32017-11-02 15:27:49 +00001968 .deliver = afs_deliver_fs_give_up_all_callbacks,
1969 .destructor = afs_flat_call_destructor,
1970};
1971
1972/*
1973 * Flush all the callbacks we have on a server.
1974 */
David Howellsd2ddc772017-11-02 15:27:50 +00001975int afs_fs_give_up_all_callbacks(struct afs_net *net,
1976 struct afs_server *server,
David Howells8b2a4642017-11-02 15:27:50 +00001977 struct afs_addr_cursor *ac,
David Howellsd2ddc772017-11-02 15:27:50 +00001978 struct key *key)
David Howellsc435ee32017-11-02 15:27:49 +00001979{
1980 struct afs_call *call;
1981 __be32 *bp;
1982
1983 _enter("");
1984
David Howellsd2ddc772017-11-02 15:27:50 +00001985 call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
David Howellsc435ee32017-11-02 15:27:49 +00001986 if (!call)
1987 return -ENOMEM;
1988
1989 call->key = key;
1990
1991 /* marshall the parameters */
1992 bp = call->request;
1993 *bp++ = htonl(FSGIVEUPALLCALLBACKS);
1994
1995 /* Can't take a ref on server */
David Howellsd2ddc772017-11-02 15:27:50 +00001996 return afs_make_call(ac, call, GFP_NOFS, false);
1997}
1998
1999/*
2000 * Deliver reply data to an FS.GetCapabilities operation.
2001 */
2002static int afs_deliver_fs_get_capabilities(struct afs_call *call)
2003{
2004 u32 count;
2005 int ret;
2006
2007 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
2008
2009again:
2010 switch (call->unmarshall) {
2011 case 0:
2012 call->offset = 0;
2013 call->unmarshall++;
2014
2015 /* Extract the capabilities word count */
2016 case 1:
2017 ret = afs_extract_data(call, &call->tmp,
2018 1 * sizeof(__be32),
2019 true);
2020 if (ret < 0)
2021 return ret;
2022
2023 count = ntohl(call->tmp);
2024
2025 call->count = count;
2026 call->count2 = count;
2027 call->offset = 0;
2028 call->unmarshall++;
2029
2030 /* Extract capabilities words */
2031 case 2:
2032 count = min(call->count, 16U);
2033 ret = afs_extract_data(call, call->buffer,
2034 count * sizeof(__be32),
2035 call->count > 16);
2036 if (ret < 0)
2037 return ret;
2038
2039 /* TODO: Examine capabilities */
2040
2041 call->count -= count;
2042 if (call->count > 0)
2043 goto again;
2044 call->offset = 0;
2045 call->unmarshall++;
2046 break;
2047 }
2048
2049 _leave(" = 0 [done]");
2050 return 0;
2051}
2052
2053/*
2054 * FS.GetCapabilities operation type
2055 */
2056static const struct afs_call_type afs_RXFSGetCapabilities = {
2057 .name = "FS.GetCapabilities",
David Howells025db802017-11-02 15:27:51 +00002058 .op = afs_FS_GetCapabilities,
David Howellsd2ddc772017-11-02 15:27:50 +00002059 .deliver = afs_deliver_fs_get_capabilities,
2060 .destructor = afs_flat_call_destructor,
2061};
2062
2063/*
2064 * Probe a fileserver for the capabilities that it supports. This can
2065 * return up to 196 words.
2066 */
2067int afs_fs_get_capabilities(struct afs_net *net,
2068 struct afs_server *server,
2069 struct afs_addr_cursor *ac,
2070 struct key *key)
2071{
2072 struct afs_call *call;
2073 __be32 *bp;
2074
2075 _enter("");
2076
2077 call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
2078 if (!call)
2079 return -ENOMEM;
2080
2081 call->key = key;
2082
2083 /* marshall the parameters */
2084 bp = call->request;
2085 *bp++ = htonl(FSGETCAPABILITIES);
2086
2087 /* Can't take a ref on server */
David Howells025db802017-11-02 15:27:51 +00002088 trace_afs_make_fs_call(call, NULL);
David Howellsd2ddc772017-11-02 15:27:50 +00002089 return afs_make_call(ac, call, GFP_NOFS, false);
David Howellse8d6c552007-07-15 23:40:12 -07002090}
David Howells5cf9dd52018-04-09 21:12:31 +01002091
2092/*
2093 * Deliver reply data to an FS.FetchStatus with no vnode.
2094 */
2095static int afs_deliver_fs_fetch_status(struct afs_call *call)
2096{
2097 struct afs_file_status *status = call->reply[1];
2098 struct afs_callback *callback = call->reply[2];
2099 struct afs_volsync *volsync = call->reply[3];
2100 struct afs_vnode *vnode = call->reply[0];
2101 const __be32 *bp;
2102 int ret;
2103
2104 ret = afs_transfer_reply(call);
2105 if (ret < 0)
2106 return ret;
2107
2108 _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
2109
2110 /* unmarshall the reply once we've received all of it */
2111 bp = call->buffer;
David Howellsc875c762018-05-23 11:32:06 +01002112 afs_decode_status(call, &bp, status, vnode,
2113 &call->expected_version, NULL);
David Howells5cf9dd52018-04-09 21:12:31 +01002114 callback[call->count].version = ntohl(bp[0]);
2115 callback[call->count].expiry = ntohl(bp[1]);
2116 callback[call->count].type = ntohl(bp[2]);
2117 if (vnode)
2118 xdr_decode_AFSCallBack(call, vnode, &bp);
2119 else
2120 bp += 3;
2121 if (volsync)
2122 xdr_decode_AFSVolSync(&bp, volsync);
2123
2124 _leave(" = 0 [done]");
2125 return 0;
2126}
2127
2128/*
2129 * FS.FetchStatus operation type
2130 */
2131static const struct afs_call_type afs_RXFSFetchStatus = {
2132 .name = "FS.FetchStatus",
2133 .op = afs_FS_FetchStatus,
2134 .deliver = afs_deliver_fs_fetch_status,
2135 .destructor = afs_flat_call_destructor,
2136};
2137
2138/*
2139 * Fetch the status information for a fid without needing a vnode handle.
2140 */
2141int afs_fs_fetch_status(struct afs_fs_cursor *fc,
2142 struct afs_net *net,
2143 struct afs_fid *fid,
2144 struct afs_file_status *status,
2145 struct afs_callback *callback,
2146 struct afs_volsync *volsync)
2147{
2148 struct afs_call *call;
2149 __be32 *bp;
2150
2151 _enter(",%x,{%x:%u},,",
2152 key_serial(fc->key), fid->vid, fid->vnode);
2153
2154 call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
2155 if (!call) {
2156 fc->ac.error = -ENOMEM;
2157 return -ENOMEM;
2158 }
2159
2160 call->key = fc->key;
2161 call->reply[0] = NULL; /* vnode for fid[0] */
2162 call->reply[1] = status;
2163 call->reply[2] = callback;
2164 call->reply[3] = volsync;
David Howells0c3a5ac2018-04-06 14:17:24 +01002165 call->expected_version = 1; /* vnode->status.data_version */
David Howells5cf9dd52018-04-09 21:12:31 +01002166
2167 /* marshall the parameters */
2168 bp = call->request;
2169 bp[0] = htonl(FSFETCHSTATUS);
2170 bp[1] = htonl(fid->vid);
2171 bp[2] = htonl(fid->vnode);
2172 bp[3] = htonl(fid->unique);
2173
2174 call->cb_break = fc->cb_break;
2175 afs_use_fs_server(call, fc->cbi);
2176 trace_afs_make_fs_call(call, fid);
2177 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
2178}
2179
2180/*
2181 * Deliver reply data to an FS.InlineBulkStatus call
2182 */
2183static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
2184{
2185 struct afs_file_status *statuses;
2186 struct afs_callback *callbacks;
2187 struct afs_vnode *vnode = call->reply[0];
2188 const __be32 *bp;
2189 u32 tmp;
2190 int ret;
2191
2192 _enter("{%u}", call->unmarshall);
2193
2194 switch (call->unmarshall) {
2195 case 0:
2196 call->offset = 0;
2197 call->unmarshall++;
2198
2199 /* Extract the file status count and array in two steps */
2200 case 1:
2201 _debug("extract status count");
2202 ret = afs_extract_data(call, &call->tmp, 4, true);
2203 if (ret < 0)
2204 return ret;
2205
2206 tmp = ntohl(call->tmp);
2207 _debug("status count: %u/%u", tmp, call->count2);
2208 if (tmp != call->count2)
David Howells5f702c82018-04-06 14:17:25 +01002209 return afs_protocol_error(call, -EBADMSG);
David Howells5cf9dd52018-04-09 21:12:31 +01002210
2211 call->count = 0;
2212 call->unmarshall++;
2213 more_counts:
2214 call->offset = 0;
2215
2216 case 2:
2217 _debug("extract status array %u", call->count);
2218 ret = afs_extract_data(call, call->buffer, 21 * 4, true);
2219 if (ret < 0)
2220 return ret;
2221
2222 bp = call->buffer;
2223 statuses = call->reply[1];
David Howellsc875c762018-05-23 11:32:06 +01002224 if (afs_decode_status(call, &bp, &statuses[call->count],
2225 call->count == 0 ? vnode : NULL,
2226 NULL, NULL) < 0)
David Howells5f702c82018-04-06 14:17:25 +01002227 return afs_protocol_error(call, -EBADMSG);
David Howells5cf9dd52018-04-09 21:12:31 +01002228
2229 call->count++;
2230 if (call->count < call->count2)
2231 goto more_counts;
2232
2233 call->count = 0;
2234 call->unmarshall++;
2235 call->offset = 0;
2236
2237 /* Extract the callback count and array in two steps */
2238 case 3:
2239 _debug("extract CB count");
2240 ret = afs_extract_data(call, &call->tmp, 4, true);
2241 if (ret < 0)
2242 return ret;
2243
2244 tmp = ntohl(call->tmp);
2245 _debug("CB count: %u", tmp);
2246 if (tmp != call->count2)
David Howells5f702c82018-04-06 14:17:25 +01002247 return afs_protocol_error(call, -EBADMSG);
David Howells5cf9dd52018-04-09 21:12:31 +01002248 call->count = 0;
2249 call->unmarshall++;
2250 more_cbs:
2251 call->offset = 0;
2252
2253 case 4:
2254 _debug("extract CB array");
2255 ret = afs_extract_data(call, call->buffer, 3 * 4, true);
2256 if (ret < 0)
2257 return ret;
2258
2259 _debug("unmarshall CB array");
2260 bp = call->buffer;
2261 callbacks = call->reply[2];
2262 callbacks[call->count].version = ntohl(bp[0]);
2263 callbacks[call->count].expiry = ntohl(bp[1]);
2264 callbacks[call->count].type = ntohl(bp[2]);
2265 statuses = call->reply[1];
2266 if (call->count == 0 && vnode && statuses[0].abort_code == 0)
2267 xdr_decode_AFSCallBack(call, vnode, &bp);
2268 call->count++;
2269 if (call->count < call->count2)
2270 goto more_cbs;
2271
2272 call->offset = 0;
2273 call->unmarshall++;
2274
2275 case 5:
2276 ret = afs_extract_data(call, call->buffer, 6 * 4, false);
2277 if (ret < 0)
2278 return ret;
2279
2280 bp = call->buffer;
2281 if (call->reply[3])
2282 xdr_decode_AFSVolSync(&bp, call->reply[3]);
2283
2284 call->offset = 0;
2285 call->unmarshall++;
2286
2287 case 6:
2288 break;
2289 }
2290
2291 _leave(" = 0 [done]");
2292 return 0;
2293}
2294
2295/*
2296 * FS.InlineBulkStatus operation type
2297 */
2298static const struct afs_call_type afs_RXFSInlineBulkStatus = {
2299 .name = "FS.InlineBulkStatus",
2300 .op = afs_FS_InlineBulkStatus,
2301 .deliver = afs_deliver_fs_inline_bulk_status,
2302 .destructor = afs_flat_call_destructor,
2303};
2304
2305/*
2306 * Fetch the status information for up to 50 files
2307 */
2308int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
2309 struct afs_net *net,
2310 struct afs_fid *fids,
2311 struct afs_file_status *statuses,
2312 struct afs_callback *callbacks,
2313 unsigned int nr_fids,
2314 struct afs_volsync *volsync)
2315{
2316 struct afs_call *call;
2317 __be32 *bp;
2318 int i;
2319
2320 _enter(",%x,{%x:%u},%u",
2321 key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids);
2322
2323 call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus,
2324 (2 + nr_fids * 3) * 4,
2325 21 * 4);
2326 if (!call) {
2327 fc->ac.error = -ENOMEM;
2328 return -ENOMEM;
2329 }
2330
2331 call->key = fc->key;
2332 call->reply[0] = NULL; /* vnode for fid[0] */
2333 call->reply[1] = statuses;
2334 call->reply[2] = callbacks;
2335 call->reply[3] = volsync;
2336 call->count2 = nr_fids;
2337
2338 /* marshall the parameters */
2339 bp = call->request;
2340 *bp++ = htonl(FSINLINEBULKSTATUS);
2341 *bp++ = htonl(nr_fids);
2342 for (i = 0; i < nr_fids; i++) {
2343 *bp++ = htonl(fids[i].vid);
2344 *bp++ = htonl(fids[i].vnode);
2345 *bp++ = htonl(fids[i].unique);
2346 }
2347
2348 call->cb_break = fc->cb_break;
2349 afs_use_fs_server(call, fc->cbi);
2350 trace_afs_make_fs_call(call, &fids[0]);
2351 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
2352}