blob: bf8904a1a58fb6e6f89ac51c03f455a56fb1a95a [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "internal.h"
David Howells08e0e7c2007-04-26 15:55:03 -070017#include "afs_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
Linus Torvalds1da177e2005-04-16 15:20:36 -070019/*
David Howells6db3ac32017-03-16 16:27:44 +000020 * We need somewhere to discard into in case the server helpfully returns more
21 * than we asked for in FS.FetchData{,64}.
22 */
23static u8 afs_discard_buffer[64];
24
25/*
David Howells260a9802007-04-26 15:59:35 -070026 * decode an AFSFid block
27 */
28static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
29{
30 const __be32 *bp = *_bp;
31
32 fid->vid = ntohl(*bp++);
33 fid->vnode = ntohl(*bp++);
34 fid->unique = ntohl(*bp++);
35 *_bp = bp;
36}
37
38/*
David Howells08e0e7c2007-04-26 15:55:03 -070039 * decode an AFSFetchStatus block
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 */
David Howells08e0e7c2007-04-26 15:55:03 -070041static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
David Howells260a9802007-04-26 15:59:35 -070042 struct afs_file_status *status,
David Howells31143d52007-05-09 02:33:46 -070043 struct afs_vnode *vnode,
44 afs_dataversion_t *store_version)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045{
David Howells31143d52007-05-09 02:33:46 -070046 afs_dataversion_t expected_version;
David Howells08e0e7c2007-04-26 15:55:03 -070047 const __be32 *bp = *_bp;
48 umode_t mode;
David Howells260a9802007-04-26 15:59:35 -070049 u64 data_version, size;
David Howells08e0e7c2007-04-26 15:55:03 -070050 u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
Eric W. Biedermana0a53862012-02-07 16:20:48 -080051 kuid_t owner;
52 kgid_t group;
David Howells08e0e7c2007-04-26 15:55:03 -070053
54#define EXTRACT(DST) \
55 do { \
56 u32 x = ntohl(*bp++); \
57 changed |= DST - x; \
58 DST = x; \
59 } while (0)
60
David Howells260a9802007-04-26 15:59:35 -070061 status->if_version = ntohl(*bp++);
62 EXTRACT(status->type);
63 EXTRACT(status->nlink);
64 size = ntohl(*bp++);
David Howells08e0e7c2007-04-26 15:55:03 -070065 data_version = ntohl(*bp++);
David Howells260a9802007-04-26 15:59:35 -070066 EXTRACT(status->author);
Eric W. Biedermana0a53862012-02-07 16:20:48 -080067 owner = make_kuid(&init_user_ns, ntohl(*bp++));
68 changed |= !uid_eq(owner, status->owner);
69 status->owner = owner;
David Howells260a9802007-04-26 15:59:35 -070070 EXTRACT(status->caller_access); /* call ticket dependent */
71 EXTRACT(status->anon_access);
72 EXTRACT(status->mode);
73 EXTRACT(status->parent.vnode);
74 EXTRACT(status->parent.unique);
David Howells08e0e7c2007-04-26 15:55:03 -070075 bp++; /* seg size */
David Howells260a9802007-04-26 15:59:35 -070076 status->mtime_client = ntohl(*bp++);
77 status->mtime_server = ntohl(*bp++);
Eric W. Biedermana0a53862012-02-07 16:20:48 -080078 group = make_kgid(&init_user_ns, ntohl(*bp++));
79 changed |= !gid_eq(group, status->group);
80 status->group = group;
David Howells08e0e7c2007-04-26 15:55:03 -070081 bp++; /* sync counter */
82 data_version |= (u64) ntohl(*bp++) << 32;
David Howellse8d6c552007-07-15 23:40:12 -070083 EXTRACT(status->lock_count);
David Howells260a9802007-04-26 15:59:35 -070084 size |= (u64) ntohl(*bp++) << 32;
85 bp++; /* spare 4 */
David Howells08e0e7c2007-04-26 15:55:03 -070086 *_bp = bp;
87
David Howells260a9802007-04-26 15:59:35 -070088 if (size != status->size) {
89 status->size = size;
90 changed |= true;
David Howells08e0e7c2007-04-26 15:55:03 -070091 }
David Howells260a9802007-04-26 15:59:35 -070092 status->mode &= S_IALLUGO;
David Howells08e0e7c2007-04-26 15:55:03 -070093
94 _debug("vnode time %lx, %lx",
David Howells260a9802007-04-26 15:59:35 -070095 status->mtime_client, status->mtime_server);
David Howells08e0e7c2007-04-26 15:55:03 -070096
David Howells260a9802007-04-26 15:59:35 -070097 if (vnode) {
98 status->parent.vid = vnode->fid.vid;
99 if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
100 _debug("vnode changed");
101 i_size_write(&vnode->vfs_inode, size);
102 vnode->vfs_inode.i_uid = status->owner;
103 vnode->vfs_inode.i_gid = status->group;
David Howellsd6e43f72011-06-14 00:45:44 +0100104 vnode->vfs_inode.i_generation = vnode->fid.unique;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200105 set_nlink(&vnode->vfs_inode, status->nlink);
David Howells260a9802007-04-26 15:59:35 -0700106
107 mode = vnode->vfs_inode.i_mode;
108 mode &= ~S_IALLUGO;
109 mode |= status->mode;
110 barrier();
111 vnode->vfs_inode.i_mode = mode;
112 }
113
114 vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server;
115 vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime;
116 vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime;
David Howellsd6e43f72011-06-14 00:45:44 +0100117 vnode->vfs_inode.i_version = data_version;
David Howells260a9802007-04-26 15:59:35 -0700118 }
119
David Howells31143d52007-05-09 02:33:46 -0700120 expected_version = status->data_version;
121 if (store_version)
122 expected_version = *store_version;
123
124 if (expected_version != data_version) {
David Howells260a9802007-04-26 15:59:35 -0700125 status->data_version = data_version;
126 if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
127 _debug("vnode modified %llx on {%x:%u}",
David S. Millerba3e0e12007-04-26 16:06:22 -0700128 (unsigned long long) data_version,
129 vnode->fid.vid, vnode->fid.vnode);
David Howells260a9802007-04-26 15:59:35 -0700130 set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
131 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
132 }
David Howells31143d52007-05-09 02:33:46 -0700133 } else if (store_version) {
134 status->data_version = data_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 }
David Howellsec268152007-04-26 15:49:28 -0700136}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138/*
David Howells08e0e7c2007-04-26 15:55:03 -0700139 * decode an AFSCallBack block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 */
David Howells08e0e7c2007-04-26 15:55:03 -0700141static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
David Howells08e0e7c2007-04-26 15:55:03 -0700143 const __be32 *bp = *_bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
David Howells08e0e7c2007-04-26 15:55:03 -0700145 vnode->cb_version = ntohl(*bp++);
146 vnode->cb_expiry = ntohl(*bp++);
147 vnode->cb_type = ntohl(*bp++);
148 vnode->cb_expires = vnode->cb_expiry + get_seconds();
149 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700150}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
David Howells260a9802007-04-26 15:59:35 -0700152static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
153 struct afs_callback *cb)
154{
155 const __be32 *bp = *_bp;
156
157 cb->version = ntohl(*bp++);
158 cb->expiry = ntohl(*bp++);
159 cb->type = ntohl(*bp++);
160 *_bp = bp;
161}
162
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163/*
David Howells08e0e7c2007-04-26 15:55:03 -0700164 * decode an AFSVolSync block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 */
David Howells08e0e7c2007-04-26 15:55:03 -0700166static void xdr_decode_AFSVolSync(const __be32 **_bp,
167 struct afs_volsync *volsync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168{
David Howells08e0e7c2007-04-26 15:55:03 -0700169 const __be32 *bp = *_bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
David Howells08e0e7c2007-04-26 15:55:03 -0700171 volsync->creation = ntohl(*bp++);
172 bp++; /* spare2 */
173 bp++; /* spare3 */
174 bp++; /* spare4 */
175 bp++; /* spare5 */
176 bp++; /* spare6 */
177 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700178}
David Howells08e0e7c2007-04-26 15:55:03 -0700179
180/*
David Howells31143d52007-05-09 02:33:46 -0700181 * encode the requested attributes into an AFSStoreStatus block
182 */
183static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
184{
185 __be32 *bp = *_bp;
186 u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
187
188 mask = 0;
189 if (attr->ia_valid & ATTR_MTIME) {
190 mask |= AFS_SET_MTIME;
191 mtime = attr->ia_mtime.tv_sec;
192 }
193
194 if (attr->ia_valid & ATTR_UID) {
195 mask |= AFS_SET_OWNER;
Eric W. Biedermana0a53862012-02-07 16:20:48 -0800196 owner = from_kuid(&init_user_ns, attr->ia_uid);
David Howells31143d52007-05-09 02:33:46 -0700197 }
198
199 if (attr->ia_valid & ATTR_GID) {
200 mask |= AFS_SET_GROUP;
Eric W. Biedermana0a53862012-02-07 16:20:48 -0800201 group = from_kgid(&init_user_ns, attr->ia_gid);
David Howells31143d52007-05-09 02:33:46 -0700202 }
203
204 if (attr->ia_valid & ATTR_MODE) {
205 mask |= AFS_SET_MODE;
206 mode = attr->ia_mode & S_IALLUGO;
207 }
208
209 *bp++ = htonl(mask);
210 *bp++ = htonl(mtime);
211 *bp++ = htonl(owner);
212 *bp++ = htonl(group);
213 *bp++ = htonl(mode);
214 *bp++ = 0; /* segment size */
215 *_bp = bp;
216}
217
218/*
David Howells45222b92007-05-10 22:22:20 -0700219 * decode an AFSFetchVolumeStatus block
220 */
221static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
222 struct afs_volume_status *vs)
223{
224 const __be32 *bp = *_bp;
225
226 vs->vid = ntohl(*bp++);
227 vs->parent_id = ntohl(*bp++);
228 vs->online = ntohl(*bp++);
229 vs->in_service = ntohl(*bp++);
230 vs->blessed = ntohl(*bp++);
231 vs->needs_salvage = ntohl(*bp++);
232 vs->type = ntohl(*bp++);
233 vs->min_quota = ntohl(*bp++);
234 vs->max_quota = ntohl(*bp++);
235 vs->blocks_in_use = ntohl(*bp++);
236 vs->part_blocks_avail = ntohl(*bp++);
237 vs->part_max_blocks = ntohl(*bp++);
238 *_bp = bp;
239}
240
241/*
David Howells08e0e7c2007-04-26 15:55:03 -0700242 * deliver reply data to an FS.FetchStatus
243 */
David Howellsd0016482016-08-30 20:42:14 +0100244static int afs_deliver_fs_fetch_status(struct afs_call *call)
David Howells08e0e7c2007-04-26 15:55:03 -0700245{
David Howells260a9802007-04-26 15:59:35 -0700246 struct afs_vnode *vnode = call->reply;
David Howells08e0e7c2007-04-26 15:55:03 -0700247 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100248 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700249
David Howellsd0016482016-08-30 20:42:14 +0100250 _enter("");
David Howells08e0e7c2007-04-26 15:55:03 -0700251
David Howellsd0016482016-08-30 20:42:14 +0100252 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100253 if (ret < 0)
254 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700255
256 /* unmarshall the reply once we've received all of it */
257 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700258 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700259 xdr_decode_AFSCallBack(&bp, vnode);
David Howells08e0e7c2007-04-26 15:55:03 -0700260 if (call->reply2)
261 xdr_decode_AFSVolSync(&bp, call->reply2);
262
263 _leave(" = 0 [done]");
264 return 0;
265}
266
267/*
268 * FS.FetchStatus operation type
269 */
270static const struct afs_call_type afs_RXFSFetchStatus = {
David Howells00d3b7a2007-04-26 15:57:07 -0700271 .name = "FS.FetchStatus",
David Howells08e0e7c2007-04-26 15:55:03 -0700272 .deliver = afs_deliver_fs_fetch_status,
273 .abort_to_error = afs_abort_to_error,
274 .destructor = afs_flat_call_destructor,
275};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277/*
278 * fetch the status information for a file
279 */
David Howells08e0e7c2007-04-26 15:55:03 -0700280int afs_fs_fetch_file_status(struct afs_server *server,
David Howells00d3b7a2007-04-26 15:57:07 -0700281 struct key *key,
David Howells08e0e7c2007-04-26 15:55:03 -0700282 struct afs_vnode *vnode,
283 struct afs_volsync *volsync,
David Howells56ff9c82017-01-05 10:38:36 +0000284 bool async)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285{
David Howells08e0e7c2007-04-26 15:55:03 -0700286 struct afs_call *call;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 __be32 *bp;
288
David Howells416351f2007-05-09 02:33:45 -0700289 _enter(",%x,{%x:%u},,",
David Howells260a9802007-04-26 15:59:35 -0700290 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
David Howells260a9802007-04-26 15:59:35 -0700292 call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700293 if (!call)
294 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
David Howells00d3b7a2007-04-26 15:57:07 -0700296 call->key = key;
David Howells08e0e7c2007-04-26 15:55:03 -0700297 call->reply = vnode;
298 call->reply2 = volsync;
299 call->service_id = FS_SERVICE;
300 call->port = htons(AFS_FS_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
302 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700303 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 bp[0] = htonl(FSFETCHSTATUS);
305 bp[1] = htonl(vnode->fid.vid);
306 bp[2] = htonl(vnode->fid.vnode);
307 bp[3] = htonl(vnode->fid.unique);
308
David Howells56ff9c82017-01-05 10:38:36 +0000309 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsec268152007-04-26 15:49:28 -0700310}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312/*
David Howells08e0e7c2007-04-26 15:55:03 -0700313 * deliver reply data to an FS.FetchData
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 */
David Howellsd0016482016-08-30 20:42:14 +0100315static int afs_deliver_fs_fetch_data(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
David Howells260a9802007-04-26 15:59:35 -0700317 struct afs_vnode *vnode = call->reply;
David Howells196ee9c2017-01-05 10:38:34 +0000318 struct afs_read *req = call->reply3;
David Howells08e0e7c2007-04-26 15:55:03 -0700319 const __be32 *bp;
David Howells196ee9c2017-01-05 10:38:34 +0000320 unsigned int size;
David Howells08e0e7c2007-04-26 15:55:03 -0700321 void *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700323
David Howells196ee9c2017-01-05 10:38:34 +0000324 _enter("{%u,%zu/%u;%u/%llu}",
325 call->unmarshall, call->offset, call->count,
326 req->remain, req->actual_len);
David Howells08e0e7c2007-04-26 15:55:03 -0700327
328 switch (call->unmarshall) {
329 case 0:
David Howells196ee9c2017-01-05 10:38:34 +0000330 req->actual_len = 0;
David Howells08e0e7c2007-04-26 15:55:03 -0700331 call->offset = 0;
332 call->unmarshall++;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700333 if (call->operation_ID != FSFETCHDATA64) {
334 call->unmarshall++;
335 goto no_msw;
336 }
David Howells08e0e7c2007-04-26 15:55:03 -0700337
David Howellsb9b1f8d2007-05-10 03:15:21 -0700338 /* extract the upper part of the returned data length of an
339 * FSFETCHDATA64 op (which should always be 0 using this
340 * client) */
David Howells08e0e7c2007-04-26 15:55:03 -0700341 case 1:
David Howellsb9b1f8d2007-05-10 03:15:21 -0700342 _debug("extract data length (MSW)");
David Howellsd0016482016-08-30 20:42:14 +0100343 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +0100344 if (ret < 0)
345 return ret;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700346
David Howells196ee9c2017-01-05 10:38:34 +0000347 req->actual_len = ntohl(call->tmp);
348 req->actual_len <<= 32;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700349 call->offset = 0;
350 call->unmarshall++;
351
352 no_msw:
353 /* extract the returned data length */
354 case 2:
David Howells08e0e7c2007-04-26 15:55:03 -0700355 _debug("extract data length");
David Howellsd0016482016-08-30 20:42:14 +0100356 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +0100357 if (ret < 0)
358 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700359
David Howells196ee9c2017-01-05 10:38:34 +0000360 req->actual_len |= ntohl(call->tmp);
361 _debug("DATA length: %llu", req->actual_len);
David Howells196ee9c2017-01-05 10:38:34 +0000362
363 req->remain = req->actual_len;
364 call->offset = req->pos & (PAGE_SIZE - 1);
365 req->index = 0;
366 if (req->actual_len == 0)
367 goto no_more_data;
David Howells08e0e7c2007-04-26 15:55:03 -0700368 call->unmarshall++;
369
David Howells196ee9c2017-01-05 10:38:34 +0000370 begin_page:
David Howells6db3ac32017-03-16 16:27:44 +0000371 ASSERTCMP(req->index, <, req->nr_pages);
David Howells196ee9c2017-01-05 10:38:34 +0000372 if (req->remain > PAGE_SIZE - call->offset)
373 size = PAGE_SIZE - call->offset;
374 else
375 size = req->remain;
376 call->count = call->offset + size;
377 ASSERTCMP(call->count, <=, PAGE_SIZE);
378 req->remain -= size;
379
David Howells08e0e7c2007-04-26 15:55:03 -0700380 /* extract the returned data */
David Howellsb9b1f8d2007-05-10 03:15:21 -0700381 case 3:
David Howells196ee9c2017-01-05 10:38:34 +0000382 _debug("extract data %u/%llu %zu/%u",
383 req->remain, req->actual_len, call->offset, call->count);
384
385 buffer = kmap(req->pages[req->index]);
386 ret = afs_extract_data(call, buffer, call->count, true);
387 kunmap(req->pages[req->index]);
388 if (ret < 0)
389 return ret;
390 if (call->offset == PAGE_SIZE) {
391 if (req->page_done)
392 req->page_done(call, req);
393 if (req->remain > 0) {
David Howells196ee9c2017-01-05 10:38:34 +0000394 call->offset = 0;
David Howells6db3ac32017-03-16 16:27:44 +0000395 req->index++;
396 if (req->index >= req->nr_pages)
397 goto begin_discard;
David Howells196ee9c2017-01-05 10:38:34 +0000398 goto begin_page;
399 }
David Howells08e0e7c2007-04-26 15:55:03 -0700400 }
David Howells6db3ac32017-03-16 16:27:44 +0000401 goto no_more_data;
402
403 /* Discard any excess data the server gave us */
404 begin_discard:
405 case 4:
406 size = min_t(size_t, sizeof(afs_discard_buffer), req->remain);
407 call->count = size;
408 _debug("extract discard %u/%llu %zu/%u",
409 req->remain, req->actual_len, call->offset, call->count);
410
411 call->offset = 0;
412 ret = afs_extract_data(call, afs_discard_buffer, call->count, true);
413 req->remain -= call->offset;
414 if (ret < 0)
415 return ret;
416 if (req->remain > 0)
417 goto begin_discard;
David Howells08e0e7c2007-04-26 15:55:03 -0700418
David Howells196ee9c2017-01-05 10:38:34 +0000419 no_more_data:
David Howells08e0e7c2007-04-26 15:55:03 -0700420 call->offset = 0;
David Howells6db3ac32017-03-16 16:27:44 +0000421 call->unmarshall = 5;
David Howells08e0e7c2007-04-26 15:55:03 -0700422
423 /* extract the metadata */
David Howells6db3ac32017-03-16 16:27:44 +0000424 case 5:
David Howellsd0016482016-08-30 20:42:14 +0100425 ret = afs_extract_data(call, call->buffer,
426 (21 + 3 + 6) * 4, false);
David Howells372ee162016-08-03 14:11:40 +0100427 if (ret < 0)
428 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700429
430 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700431 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700432 xdr_decode_AFSCallBack(&bp, vnode);
David Howells08e0e7c2007-04-26 15:55:03 -0700433 if (call->reply2)
434 xdr_decode_AFSVolSync(&bp, call->reply2);
435
436 call->offset = 0;
437 call->unmarshall++;
438
David Howells6db3ac32017-03-16 16:27:44 +0000439 case 6:
David Howells08e0e7c2007-04-26 15:55:03 -0700440 break;
441 }
442
David Howells6db3ac32017-03-16 16:27:44 +0000443 for (; req->index < req->nr_pages; req->index++) {
444 if (call->count < PAGE_SIZE)
445 zero_user_segment(req->pages[req->index],
446 call->count, PAGE_SIZE);
David Howells196ee9c2017-01-05 10:38:34 +0000447 if (req->page_done)
448 req->page_done(call, req);
David Howells6db3ac32017-03-16 16:27:44 +0000449 call->count = 0;
David Howells416351f2007-05-09 02:33:45 -0700450 }
451
David Howells08e0e7c2007-04-26 15:55:03 -0700452 _leave(" = 0 [done]");
453 return 0;
454}
455
David Howells196ee9c2017-01-05 10:38:34 +0000456static void afs_fetch_data_destructor(struct afs_call *call)
457{
458 struct afs_read *req = call->reply3;
459
460 afs_put_read(req);
461 afs_flat_call_destructor(call);
462}
463
David Howells08e0e7c2007-04-26 15:55:03 -0700464/*
465 * FS.FetchData operation type
466 */
467static const struct afs_call_type afs_RXFSFetchData = {
David Howells00d3b7a2007-04-26 15:57:07 -0700468 .name = "FS.FetchData",
David Howells08e0e7c2007-04-26 15:55:03 -0700469 .deliver = afs_deliver_fs_fetch_data,
470 .abort_to_error = afs_abort_to_error,
David Howells196ee9c2017-01-05 10:38:34 +0000471 .destructor = afs_fetch_data_destructor,
David Howells08e0e7c2007-04-26 15:55:03 -0700472};
473
David Howellsb9b1f8d2007-05-10 03:15:21 -0700474static const struct afs_call_type afs_RXFSFetchData64 = {
475 .name = "FS.FetchData64",
476 .deliver = afs_deliver_fs_fetch_data,
477 .abort_to_error = afs_abort_to_error,
David Howells196ee9c2017-01-05 10:38:34 +0000478 .destructor = afs_fetch_data_destructor,
David Howellsb9b1f8d2007-05-10 03:15:21 -0700479};
480
481/*
482 * fetch data from a very large file
483 */
484static int afs_fs_fetch_data64(struct afs_server *server,
485 struct key *key,
486 struct afs_vnode *vnode,
David Howells196ee9c2017-01-05 10:38:34 +0000487 struct afs_read *req,
David Howells56ff9c82017-01-05 10:38:36 +0000488 bool async)
David Howellsb9b1f8d2007-05-10 03:15:21 -0700489{
490 struct afs_call *call;
491 __be32 *bp;
492
493 _enter("");
494
David Howellsb9b1f8d2007-05-10 03:15:21 -0700495 call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
496 if (!call)
497 return -ENOMEM;
498
499 call->key = key;
500 call->reply = vnode;
501 call->reply2 = NULL; /* volsync */
David Howells196ee9c2017-01-05 10:38:34 +0000502 call->reply3 = req;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700503 call->service_id = FS_SERVICE;
504 call->port = htons(AFS_FS_PORT);
505 call->operation_ID = FSFETCHDATA64;
506
507 /* marshall the parameters */
508 bp = call->request;
509 bp[0] = htonl(FSFETCHDATA64);
510 bp[1] = htonl(vnode->fid.vid);
511 bp[2] = htonl(vnode->fid.vnode);
512 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000513 bp[4] = htonl(upper_32_bits(req->pos));
514 bp[5] = htonl(lower_32_bits(req->pos));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700515 bp[6] = 0;
David Howells196ee9c2017-01-05 10:38:34 +0000516 bp[7] = htonl(lower_32_bits(req->len));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700517
David Howells196ee9c2017-01-05 10:38:34 +0000518 atomic_inc(&req->usage);
David Howells56ff9c82017-01-05 10:38:36 +0000519 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700520}
521
David Howells08e0e7c2007-04-26 15:55:03 -0700522/*
523 * fetch data from a file
524 */
525int afs_fs_fetch_data(struct afs_server *server,
David Howells00d3b7a2007-04-26 15:57:07 -0700526 struct key *key,
David Howells08e0e7c2007-04-26 15:55:03 -0700527 struct afs_vnode *vnode,
David Howells196ee9c2017-01-05 10:38:34 +0000528 struct afs_read *req,
David Howells56ff9c82017-01-05 10:38:36 +0000529 bool async)
David Howells08e0e7c2007-04-26 15:55:03 -0700530{
531 struct afs_call *call;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 __be32 *bp;
533
David Howells196ee9c2017-01-05 10:38:34 +0000534 if (upper_32_bits(req->pos) ||
535 upper_32_bits(req->len) ||
536 upper_32_bits(req->pos + req->len))
David Howells56ff9c82017-01-05 10:38:36 +0000537 return afs_fs_fetch_data64(server, key, vnode, req, async);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700538
David Howells08e0e7c2007-04-26 15:55:03 -0700539 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
David Howells260a9802007-04-26 15:59:35 -0700541 call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700542 if (!call)
543 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
David Howells00d3b7a2007-04-26 15:57:07 -0700545 call->key = key;
David Howells08e0e7c2007-04-26 15:55:03 -0700546 call->reply = vnode;
David Howells260a9802007-04-26 15:59:35 -0700547 call->reply2 = NULL; /* volsync */
David Howells196ee9c2017-01-05 10:38:34 +0000548 call->reply3 = req;
David Howells08e0e7c2007-04-26 15:55:03 -0700549 call->service_id = FS_SERVICE;
550 call->port = htons(AFS_FS_PORT);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700551 call->operation_ID = FSFETCHDATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700554 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 bp[0] = htonl(FSFETCHDATA);
David Howells08e0e7c2007-04-26 15:55:03 -0700556 bp[1] = htonl(vnode->fid.vid);
557 bp[2] = htonl(vnode->fid.vnode);
558 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000559 bp[4] = htonl(lower_32_bits(req->pos));
560 bp[5] = htonl(lower_32_bits(req->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
David Howells196ee9c2017-01-05 10:38:34 +0000562 atomic_inc(&req->usage);
David Howells56ff9c82017-01-05 10:38:36 +0000563 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsec268152007-04-26 15:49:28 -0700564}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566/*
David Howells08e0e7c2007-04-26 15:55:03 -0700567 * deliver reply data to an FS.GiveUpCallBacks
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 */
David Howellsd0016482016-08-30 20:42:14 +0100569static int afs_deliver_fs_give_up_callbacks(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
David Howellsd0016482016-08-30 20:42:14 +0100571 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
David Howells372ee162016-08-03 14:11:40 +0100573 /* shouldn't be any reply data */
David Howellsd0016482016-08-30 20:42:14 +0100574 return afs_extract_data(call, NULL, 0, false);
David Howells08e0e7c2007-04-26 15:55:03 -0700575}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
David Howells08e0e7c2007-04-26 15:55:03 -0700577/*
578 * FS.GiveUpCallBacks operation type
579 */
580static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
David Howells00d3b7a2007-04-26 15:57:07 -0700581 .name = "FS.GiveUpCallBacks",
David Howells08e0e7c2007-04-26 15:55:03 -0700582 .deliver = afs_deliver_fs_give_up_callbacks,
583 .abort_to_error = afs_abort_to_error,
584 .destructor = afs_flat_call_destructor,
585};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
David Howells08e0e7c2007-04-26 15:55:03 -0700587/*
588 * give up a set of callbacks
589 * - the callbacks are held in the server->cb_break ring
590 */
591int afs_fs_give_up_callbacks(struct afs_server *server,
David Howells56ff9c82017-01-05 10:38:36 +0000592 bool async)
David Howells08e0e7c2007-04-26 15:55:03 -0700593{
594 struct afs_call *call;
595 size_t ncallbacks;
596 __be32 *bp, *tp;
597 int loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
David Howells08e0e7c2007-04-26 15:55:03 -0700599 ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
600 ARRAY_SIZE(server->cb_break));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
David Howells08e0e7c2007-04-26 15:55:03 -0700602 _enter("{%zu},", ncallbacks);
603
604 if (ncallbacks == 0)
605 return 0;
606 if (ncallbacks > AFSCBMAX)
607 ncallbacks = AFSCBMAX;
608
609 _debug("break %zu callbacks", ncallbacks);
610
611 call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
612 12 + ncallbacks * 6 * 4, 0);
613 if (!call)
614 return -ENOMEM;
615
616 call->service_id = FS_SERVICE;
617 call->port = htons(AFS_FS_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700620 bp = call->request;
621 tp = bp + 2 + ncallbacks * 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 *bp++ = htonl(FSGIVEUPCALLBACKS);
David Howells08e0e7c2007-04-26 15:55:03 -0700623 *bp++ = htonl(ncallbacks);
624 *tp++ = htonl(ncallbacks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
David Howells08e0e7c2007-04-26 15:55:03 -0700626 atomic_sub(ncallbacks, &server->cb_break_n);
627 for (loop = ncallbacks; loop > 0; loop--) {
628 struct afs_callback *cb =
629 &server->cb_break[server->cb_break_tail];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
David Howells08e0e7c2007-04-26 15:55:03 -0700631 *bp++ = htonl(cb->fid.vid);
632 *bp++ = htonl(cb->fid.vnode);
633 *bp++ = htonl(cb->fid.unique);
634 *tp++ = htonl(cb->version);
635 *tp++ = htonl(cb->expiry);
636 *tp++ = htonl(cb->type);
637 smp_mb();
638 server->cb_break_tail =
639 (server->cb_break_tail + 1) &
640 (ARRAY_SIZE(server->cb_break) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 }
642
David Howells08e0e7c2007-04-26 15:55:03 -0700643 ASSERT(ncallbacks > 0);
644 wake_up_nr(&server->cb_break_waitq, ncallbacks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
David Howells56ff9c82017-01-05 10:38:36 +0000646 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsec268152007-04-26 15:49:28 -0700647}
David Howells260a9802007-04-26 15:59:35 -0700648
649/*
650 * deliver reply data to an FS.CreateFile or an FS.MakeDir
651 */
David Howellsd0016482016-08-30 20:42:14 +0100652static int afs_deliver_fs_create_vnode(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700653{
654 struct afs_vnode *vnode = call->reply;
655 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100656 int ret;
David Howells260a9802007-04-26 15:59:35 -0700657
David Howellsd0016482016-08-30 20:42:14 +0100658 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700659
David Howellsd0016482016-08-30 20:42:14 +0100660 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100661 if (ret < 0)
662 return ret;
David Howells260a9802007-04-26 15:59:35 -0700663
664 /* unmarshall the reply once we've received all of it */
665 bp = call->buffer;
666 xdr_decode_AFSFid(&bp, call->reply2);
David Howells31143d52007-05-09 02:33:46 -0700667 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
668 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700669 xdr_decode_AFSCallBack_raw(&bp, call->reply4);
670 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
671
672 _leave(" = 0 [done]");
673 return 0;
674}
675
676/*
677 * FS.CreateFile and FS.MakeDir operation type
678 */
679static const struct afs_call_type afs_RXFSCreateXXXX = {
680 .name = "FS.CreateXXXX",
681 .deliver = afs_deliver_fs_create_vnode,
682 .abort_to_error = afs_abort_to_error,
683 .destructor = afs_flat_call_destructor,
684};
685
686/*
687 * create a file or make a directory
688 */
689int afs_fs_create(struct afs_server *server,
690 struct key *key,
691 struct afs_vnode *vnode,
692 const char *name,
693 umode_t mode,
694 struct afs_fid *newfid,
695 struct afs_file_status *newstatus,
696 struct afs_callback *newcb,
David Howells56ff9c82017-01-05 10:38:36 +0000697 bool async)
David Howells260a9802007-04-26 15:59:35 -0700698{
699 struct afs_call *call;
700 size_t namesz, reqsz, padsz;
701 __be32 *bp;
702
703 _enter("");
704
705 namesz = strlen(name);
706 padsz = (4 - (namesz & 3)) & 3;
707 reqsz = (5 * 4) + namesz + padsz + (6 * 4);
708
709 call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
710 (3 + 21 + 21 + 3 + 6) * 4);
711 if (!call)
712 return -ENOMEM;
713
714 call->key = key;
715 call->reply = vnode;
716 call->reply2 = newfid;
717 call->reply3 = newstatus;
718 call->reply4 = newcb;
719 call->service_id = FS_SERVICE;
720 call->port = htons(AFS_FS_PORT);
721
722 /* marshall the parameters */
723 bp = call->request;
724 *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
725 *bp++ = htonl(vnode->fid.vid);
726 *bp++ = htonl(vnode->fid.vnode);
727 *bp++ = htonl(vnode->fid.unique);
728 *bp++ = htonl(namesz);
729 memcpy(bp, name, namesz);
730 bp = (void *) bp + namesz;
731 if (padsz > 0) {
732 memset(bp, 0, padsz);
733 bp = (void *) bp + padsz;
734 }
735 *bp++ = htonl(AFS_SET_MODE);
736 *bp++ = 0; /* mtime */
737 *bp++ = 0; /* owner */
738 *bp++ = 0; /* group */
739 *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
740 *bp++ = 0; /* segment size */
741
David Howells56ff9c82017-01-05 10:38:36 +0000742 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -0700743}
744
745/*
746 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
747 */
David Howellsd0016482016-08-30 20:42:14 +0100748static int afs_deliver_fs_remove(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700749{
750 struct afs_vnode *vnode = call->reply;
751 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100752 int ret;
David Howells260a9802007-04-26 15:59:35 -0700753
David Howellsd0016482016-08-30 20:42:14 +0100754 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700755
David Howellsd0016482016-08-30 20:42:14 +0100756 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100757 if (ret < 0)
758 return ret;
David Howells260a9802007-04-26 15:59:35 -0700759
760 /* unmarshall the reply once we've received all of it */
761 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700762 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700763 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
764
765 _leave(" = 0 [done]");
766 return 0;
767}
768
769/*
770 * FS.RemoveDir/FS.RemoveFile operation type
771 */
772static const struct afs_call_type afs_RXFSRemoveXXXX = {
773 .name = "FS.RemoveXXXX",
774 .deliver = afs_deliver_fs_remove,
775 .abort_to_error = afs_abort_to_error,
776 .destructor = afs_flat_call_destructor,
777};
778
779/*
780 * remove a file or directory
781 */
782int afs_fs_remove(struct afs_server *server,
783 struct key *key,
784 struct afs_vnode *vnode,
785 const char *name,
786 bool isdir,
David Howells56ff9c82017-01-05 10:38:36 +0000787 bool async)
David Howells260a9802007-04-26 15:59:35 -0700788{
789 struct afs_call *call;
790 size_t namesz, reqsz, padsz;
791 __be32 *bp;
792
793 _enter("");
794
795 namesz = strlen(name);
796 padsz = (4 - (namesz & 3)) & 3;
797 reqsz = (5 * 4) + namesz + padsz;
798
799 call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
800 if (!call)
801 return -ENOMEM;
802
803 call->key = key;
804 call->reply = vnode;
805 call->service_id = FS_SERVICE;
806 call->port = htons(AFS_FS_PORT);
807
808 /* marshall the parameters */
809 bp = call->request;
810 *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
811 *bp++ = htonl(vnode->fid.vid);
812 *bp++ = htonl(vnode->fid.vnode);
813 *bp++ = htonl(vnode->fid.unique);
814 *bp++ = htonl(namesz);
815 memcpy(bp, name, namesz);
816 bp = (void *) bp + namesz;
817 if (padsz > 0) {
818 memset(bp, 0, padsz);
819 bp = (void *) bp + padsz;
820 }
821
David Howells56ff9c82017-01-05 10:38:36 +0000822 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -0700823}
824
825/*
826 * deliver reply data to an FS.Link
827 */
David Howellsd0016482016-08-30 20:42:14 +0100828static int afs_deliver_fs_link(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700829{
830 struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
831 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 Howells31143d52007-05-09 02:33:46 -0700842 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
843 xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700844 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
845
846 _leave(" = 0 [done]");
847 return 0;
848}
849
850/*
851 * FS.Link operation type
852 */
853static const struct afs_call_type afs_RXFSLink = {
854 .name = "FS.Link",
855 .deliver = afs_deliver_fs_link,
856 .abort_to_error = afs_abort_to_error,
857 .destructor = afs_flat_call_destructor,
858};
859
860/*
861 * make a hard link
862 */
863int afs_fs_link(struct afs_server *server,
864 struct key *key,
865 struct afs_vnode *dvnode,
866 struct afs_vnode *vnode,
867 const char *name,
David Howells56ff9c82017-01-05 10:38:36 +0000868 bool async)
David Howells260a9802007-04-26 15:59:35 -0700869{
870 struct afs_call *call;
871 size_t namesz, reqsz, padsz;
872 __be32 *bp;
873
874 _enter("");
875
876 namesz = strlen(name);
877 padsz = (4 - (namesz & 3)) & 3;
878 reqsz = (5 * 4) + namesz + padsz + (3 * 4);
879
880 call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
881 if (!call)
882 return -ENOMEM;
883
884 call->key = key;
885 call->reply = dvnode;
886 call->reply2 = vnode;
887 call->service_id = FS_SERVICE;
888 call->port = htons(AFS_FS_PORT);
889
890 /* marshall the parameters */
891 bp = call->request;
892 *bp++ = htonl(FSLINK);
893 *bp++ = htonl(dvnode->fid.vid);
894 *bp++ = htonl(dvnode->fid.vnode);
895 *bp++ = htonl(dvnode->fid.unique);
896 *bp++ = htonl(namesz);
897 memcpy(bp, name, namesz);
898 bp = (void *) bp + namesz;
899 if (padsz > 0) {
900 memset(bp, 0, padsz);
901 bp = (void *) bp + padsz;
902 }
903 *bp++ = htonl(vnode->fid.vid);
904 *bp++ = htonl(vnode->fid.vnode);
905 *bp++ = htonl(vnode->fid.unique);
906
David Howells56ff9c82017-01-05 10:38:36 +0000907 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -0700908}
909
910/*
911 * deliver reply data to an FS.Symlink
912 */
David Howellsd0016482016-08-30 20:42:14 +0100913static int afs_deliver_fs_symlink(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700914{
915 struct afs_vnode *vnode = call->reply;
916 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100917 int ret;
David Howells260a9802007-04-26 15:59:35 -0700918
David Howellsd0016482016-08-30 20:42:14 +0100919 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700920
David Howellsd0016482016-08-30 20:42:14 +0100921 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100922 if (ret < 0)
923 return ret;
David Howells260a9802007-04-26 15:59:35 -0700924
925 /* unmarshall the reply once we've received all of it */
926 bp = call->buffer;
927 xdr_decode_AFSFid(&bp, call->reply2);
David Howells31143d52007-05-09 02:33:46 -0700928 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
929 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700930 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
931
932 _leave(" = 0 [done]");
933 return 0;
934}
935
936/*
937 * FS.Symlink operation type
938 */
939static const struct afs_call_type afs_RXFSSymlink = {
940 .name = "FS.Symlink",
941 .deliver = afs_deliver_fs_symlink,
942 .abort_to_error = afs_abort_to_error,
943 .destructor = afs_flat_call_destructor,
944};
945
946/*
947 * create a symbolic link
948 */
949int afs_fs_symlink(struct afs_server *server,
950 struct key *key,
951 struct afs_vnode *vnode,
952 const char *name,
953 const char *contents,
954 struct afs_fid *newfid,
955 struct afs_file_status *newstatus,
David Howells56ff9c82017-01-05 10:38:36 +0000956 bool async)
David Howells260a9802007-04-26 15:59:35 -0700957{
958 struct afs_call *call;
959 size_t namesz, reqsz, padsz, c_namesz, c_padsz;
960 __be32 *bp;
961
962 _enter("");
963
964 namesz = strlen(name);
965 padsz = (4 - (namesz & 3)) & 3;
966
967 c_namesz = strlen(contents);
968 c_padsz = (4 - (c_namesz & 3)) & 3;
969
970 reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
971
972 call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
973 (3 + 21 + 21 + 6) * 4);
974 if (!call)
975 return -ENOMEM;
976
977 call->key = key;
978 call->reply = vnode;
979 call->reply2 = newfid;
980 call->reply3 = newstatus;
981 call->service_id = FS_SERVICE;
982 call->port = htons(AFS_FS_PORT);
983
984 /* marshall the parameters */
985 bp = call->request;
986 *bp++ = htonl(FSSYMLINK);
987 *bp++ = htonl(vnode->fid.vid);
988 *bp++ = htonl(vnode->fid.vnode);
989 *bp++ = htonl(vnode->fid.unique);
990 *bp++ = htonl(namesz);
991 memcpy(bp, name, namesz);
992 bp = (void *) bp + namesz;
993 if (padsz > 0) {
994 memset(bp, 0, padsz);
995 bp = (void *) bp + padsz;
996 }
997 *bp++ = htonl(c_namesz);
998 memcpy(bp, contents, c_namesz);
999 bp = (void *) bp + c_namesz;
1000 if (c_padsz > 0) {
1001 memset(bp, 0, c_padsz);
1002 bp = (void *) bp + c_padsz;
1003 }
1004 *bp++ = htonl(AFS_SET_MODE);
1005 *bp++ = 0; /* mtime */
1006 *bp++ = 0; /* owner */
1007 *bp++ = 0; /* group */
1008 *bp++ = htonl(S_IRWXUGO); /* unix mode */
1009 *bp++ = 0; /* segment size */
1010
David Howells56ff9c82017-01-05 10:38:36 +00001011 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -07001012}
1013
1014/*
1015 * deliver reply data to an FS.Rename
1016 */
David Howellsd0016482016-08-30 20:42:14 +01001017static int afs_deliver_fs_rename(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -07001018{
1019 struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
1020 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001021 int ret;
David Howells260a9802007-04-26 15:59:35 -07001022
David Howellsd0016482016-08-30 20:42:14 +01001023 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -07001024
David Howellsd0016482016-08-30 20:42:14 +01001025 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001026 if (ret < 0)
1027 return ret;
David Howells260a9802007-04-26 15:59:35 -07001028
1029 /* unmarshall the reply once we've received all of it */
1030 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -07001031 xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
David Howells260a9802007-04-26 15:59:35 -07001032 if (new_dvnode != orig_dvnode)
David Howells31143d52007-05-09 02:33:46 -07001033 xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
1034 NULL);
David Howells260a9802007-04-26 15:59:35 -07001035 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1036
1037 _leave(" = 0 [done]");
1038 return 0;
1039}
1040
1041/*
1042 * FS.Rename operation type
1043 */
1044static const struct afs_call_type afs_RXFSRename = {
1045 .name = "FS.Rename",
1046 .deliver = afs_deliver_fs_rename,
1047 .abort_to_error = afs_abort_to_error,
1048 .destructor = afs_flat_call_destructor,
1049};
1050
1051/*
1052 * create a symbolic link
1053 */
1054int afs_fs_rename(struct afs_server *server,
1055 struct key *key,
1056 struct afs_vnode *orig_dvnode,
1057 const char *orig_name,
1058 struct afs_vnode *new_dvnode,
1059 const char *new_name,
David Howells56ff9c82017-01-05 10:38:36 +00001060 bool async)
David Howells260a9802007-04-26 15:59:35 -07001061{
1062 struct afs_call *call;
1063 size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1064 __be32 *bp;
1065
1066 _enter("");
1067
1068 o_namesz = strlen(orig_name);
1069 o_padsz = (4 - (o_namesz & 3)) & 3;
1070
1071 n_namesz = strlen(new_name);
1072 n_padsz = (4 - (n_namesz & 3)) & 3;
1073
1074 reqsz = (4 * 4) +
1075 4 + o_namesz + o_padsz +
1076 (3 * 4) +
1077 4 + n_namesz + n_padsz;
1078
1079 call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1080 if (!call)
1081 return -ENOMEM;
1082
1083 call->key = key;
1084 call->reply = orig_dvnode;
1085 call->reply2 = new_dvnode;
1086 call->service_id = FS_SERVICE;
1087 call->port = htons(AFS_FS_PORT);
1088
1089 /* marshall the parameters */
1090 bp = call->request;
1091 *bp++ = htonl(FSRENAME);
1092 *bp++ = htonl(orig_dvnode->fid.vid);
1093 *bp++ = htonl(orig_dvnode->fid.vnode);
1094 *bp++ = htonl(orig_dvnode->fid.unique);
1095 *bp++ = htonl(o_namesz);
1096 memcpy(bp, orig_name, o_namesz);
1097 bp = (void *) bp + o_namesz;
1098 if (o_padsz > 0) {
1099 memset(bp, 0, o_padsz);
1100 bp = (void *) bp + o_padsz;
1101 }
1102
1103 *bp++ = htonl(new_dvnode->fid.vid);
1104 *bp++ = htonl(new_dvnode->fid.vnode);
1105 *bp++ = htonl(new_dvnode->fid.unique);
1106 *bp++ = htonl(n_namesz);
1107 memcpy(bp, new_name, n_namesz);
1108 bp = (void *) bp + n_namesz;
1109 if (n_padsz > 0) {
1110 memset(bp, 0, n_padsz);
1111 bp = (void *) bp + n_padsz;
1112 }
1113
David Howells56ff9c82017-01-05 10:38:36 +00001114 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -07001115}
David Howells31143d52007-05-09 02:33:46 -07001116
1117/*
1118 * deliver reply data to an FS.StoreData
1119 */
David Howellsd0016482016-08-30 20:42:14 +01001120static int afs_deliver_fs_store_data(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001121{
1122 struct afs_vnode *vnode = call->reply;
1123 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001124 int ret;
David Howells31143d52007-05-09 02:33:46 -07001125
David Howellsd0016482016-08-30 20:42:14 +01001126 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001127
David Howellsd0016482016-08-30 20:42:14 +01001128 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001129 if (ret < 0)
1130 return ret;
David Howells31143d52007-05-09 02:33:46 -07001131
1132 /* unmarshall the reply once we've received all of it */
1133 bp = call->buffer;
1134 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
1135 &call->store_version);
1136 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1137
1138 afs_pages_written_back(vnode, call);
1139
1140 _leave(" = 0 [done]");
1141 return 0;
1142}
1143
1144/*
1145 * FS.StoreData operation type
1146 */
1147static const struct afs_call_type afs_RXFSStoreData = {
1148 .name = "FS.StoreData",
1149 .deliver = afs_deliver_fs_store_data,
1150 .abort_to_error = afs_abort_to_error,
1151 .destructor = afs_flat_call_destructor,
1152};
1153
David Howellsb9b1f8d2007-05-10 03:15:21 -07001154static const struct afs_call_type afs_RXFSStoreData64 = {
1155 .name = "FS.StoreData64",
1156 .deliver = afs_deliver_fs_store_data,
1157 .abort_to_error = afs_abort_to_error,
1158 .destructor = afs_flat_call_destructor,
1159};
1160
1161/*
1162 * store a set of pages to a very large file
1163 */
1164static int afs_fs_store_data64(struct afs_server *server,
1165 struct afs_writeback *wb,
1166 pgoff_t first, pgoff_t last,
1167 unsigned offset, unsigned to,
1168 loff_t size, loff_t pos, loff_t i_size,
David Howells56ff9c82017-01-05 10:38:36 +00001169 bool async)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001170{
1171 struct afs_vnode *vnode = wb->vnode;
1172 struct afs_call *call;
1173 __be32 *bp;
1174
1175 _enter(",%x,{%x:%u},,",
1176 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1177
1178 call = afs_alloc_flat_call(&afs_RXFSStoreData64,
1179 (4 + 6 + 3 * 2) * 4,
1180 (21 + 6) * 4);
1181 if (!call)
1182 return -ENOMEM;
1183
1184 call->wb = wb;
1185 call->key = wb->key;
1186 call->reply = vnode;
1187 call->service_id = FS_SERVICE;
1188 call->port = htons(AFS_FS_PORT);
1189 call->mapping = vnode->vfs_inode.i_mapping;
1190 call->first = first;
1191 call->last = last;
1192 call->first_offset = offset;
1193 call->last_to = to;
1194 call->send_pages = true;
1195 call->store_version = vnode->status.data_version + 1;
1196
1197 /* marshall the parameters */
1198 bp = call->request;
1199 *bp++ = htonl(FSSTOREDATA64);
1200 *bp++ = htonl(vnode->fid.vid);
1201 *bp++ = htonl(vnode->fid.vnode);
1202 *bp++ = htonl(vnode->fid.unique);
1203
1204 *bp++ = 0; /* mask */
1205 *bp++ = 0; /* mtime */
1206 *bp++ = 0; /* owner */
1207 *bp++ = 0; /* group */
1208 *bp++ = 0; /* unix mode */
1209 *bp++ = 0; /* segment size */
1210
1211 *bp++ = htonl(pos >> 32);
1212 *bp++ = htonl((u32) pos);
1213 *bp++ = htonl(size >> 32);
1214 *bp++ = htonl((u32) size);
1215 *bp++ = htonl(i_size >> 32);
1216 *bp++ = htonl((u32) i_size);
1217
David Howells56ff9c82017-01-05 10:38:36 +00001218 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001219}
1220
David Howells31143d52007-05-09 02:33:46 -07001221/*
1222 * store a set of pages
1223 */
1224int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
1225 pgoff_t first, pgoff_t last,
1226 unsigned offset, unsigned to,
David Howells56ff9c82017-01-05 10:38:36 +00001227 bool async)
David Howells31143d52007-05-09 02:33:46 -07001228{
1229 struct afs_vnode *vnode = wb->vnode;
1230 struct afs_call *call;
1231 loff_t size, pos, i_size;
1232 __be32 *bp;
1233
1234 _enter(",%x,{%x:%u},,",
1235 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1236
1237 size = to - offset;
1238 if (first != last)
1239 size += (loff_t)(last - first) << PAGE_SHIFT;
1240 pos = (loff_t)first << PAGE_SHIFT;
1241 pos += offset;
1242
1243 i_size = i_size_read(&vnode->vfs_inode);
1244 if (pos + size > i_size)
1245 i_size = size + pos;
1246
1247 _debug("size %llx, at %llx, i_size %llx",
1248 (unsigned long long) size, (unsigned long long) pos,
1249 (unsigned long long) i_size);
1250
David Howellsb9b1f8d2007-05-10 03:15:21 -07001251 if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
1252 return afs_fs_store_data64(server, wb, first, last, offset, to,
David Howells56ff9c82017-01-05 10:38:36 +00001253 size, pos, i_size, async);
David Howells31143d52007-05-09 02:33:46 -07001254
1255 call = afs_alloc_flat_call(&afs_RXFSStoreData,
1256 (4 + 6 + 3) * 4,
1257 (21 + 6) * 4);
1258 if (!call)
1259 return -ENOMEM;
1260
1261 call->wb = wb;
1262 call->key = wb->key;
1263 call->reply = vnode;
1264 call->service_id = FS_SERVICE;
1265 call->port = htons(AFS_FS_PORT);
1266 call->mapping = vnode->vfs_inode.i_mapping;
1267 call->first = first;
1268 call->last = last;
1269 call->first_offset = offset;
1270 call->last_to = to;
1271 call->send_pages = true;
1272 call->store_version = vnode->status.data_version + 1;
1273
1274 /* marshall the parameters */
1275 bp = call->request;
1276 *bp++ = htonl(FSSTOREDATA);
1277 *bp++ = htonl(vnode->fid.vid);
1278 *bp++ = htonl(vnode->fid.vnode);
1279 *bp++ = htonl(vnode->fid.unique);
1280
1281 *bp++ = 0; /* mask */
1282 *bp++ = 0; /* mtime */
1283 *bp++ = 0; /* owner */
1284 *bp++ = 0; /* group */
1285 *bp++ = 0; /* unix mode */
1286 *bp++ = 0; /* segment size */
1287
1288 *bp++ = htonl(pos);
1289 *bp++ = htonl(size);
1290 *bp++ = htonl(i_size);
1291
David Howells56ff9c82017-01-05 10:38:36 +00001292 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells31143d52007-05-09 02:33:46 -07001293}
1294
1295/*
1296 * deliver reply data to an FS.StoreStatus
1297 */
David Howellsd0016482016-08-30 20:42:14 +01001298static int afs_deliver_fs_store_status(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001299{
1300 afs_dataversion_t *store_version;
1301 struct afs_vnode *vnode = call->reply;
1302 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001303 int ret;
David Howells31143d52007-05-09 02:33:46 -07001304
David Howellsd0016482016-08-30 20:42:14 +01001305 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001306
David Howellsd0016482016-08-30 20:42:14 +01001307 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001308 if (ret < 0)
1309 return ret;
David Howells31143d52007-05-09 02:33:46 -07001310
1311 /* unmarshall the reply once we've received all of it */
1312 store_version = NULL;
1313 if (call->operation_ID == FSSTOREDATA)
1314 store_version = &call->store_version;
1315
1316 bp = call->buffer;
1317 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
1318 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1319
1320 _leave(" = 0 [done]");
1321 return 0;
1322}
1323
1324/*
1325 * FS.StoreStatus operation type
1326 */
1327static const struct afs_call_type afs_RXFSStoreStatus = {
1328 .name = "FS.StoreStatus",
1329 .deliver = afs_deliver_fs_store_status,
1330 .abort_to_error = afs_abort_to_error,
1331 .destructor = afs_flat_call_destructor,
1332};
1333
1334static const struct afs_call_type afs_RXFSStoreData_as_Status = {
1335 .name = "FS.StoreData",
1336 .deliver = afs_deliver_fs_store_status,
1337 .abort_to_error = afs_abort_to_error,
1338 .destructor = afs_flat_call_destructor,
1339};
1340
David Howellsb9b1f8d2007-05-10 03:15:21 -07001341static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1342 .name = "FS.StoreData64",
1343 .deliver = afs_deliver_fs_store_status,
1344 .abort_to_error = afs_abort_to_error,
1345 .destructor = afs_flat_call_destructor,
1346};
1347
1348/*
1349 * set the attributes on a very large file, using FS.StoreData rather than
1350 * FS.StoreStatus so as to alter the file size also
1351 */
1352static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
1353 struct afs_vnode *vnode, struct iattr *attr,
David Howells56ff9c82017-01-05 10:38:36 +00001354 bool async)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001355{
1356 struct afs_call *call;
1357 __be32 *bp;
1358
1359 _enter(",%x,{%x:%u},,",
1360 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1361
1362 ASSERT(attr->ia_valid & ATTR_SIZE);
1363
1364 call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
1365 (4 + 6 + 3 * 2) * 4,
1366 (21 + 6) * 4);
1367 if (!call)
1368 return -ENOMEM;
1369
1370 call->key = key;
1371 call->reply = vnode;
1372 call->service_id = FS_SERVICE;
1373 call->port = htons(AFS_FS_PORT);
1374 call->store_version = vnode->status.data_version + 1;
1375 call->operation_ID = FSSTOREDATA;
1376
1377 /* marshall the parameters */
1378 bp = call->request;
1379 *bp++ = htonl(FSSTOREDATA64);
1380 *bp++ = htonl(vnode->fid.vid);
1381 *bp++ = htonl(vnode->fid.vnode);
1382 *bp++ = htonl(vnode->fid.unique);
1383
1384 xdr_encode_AFS_StoreStatus(&bp, attr);
1385
1386 *bp++ = 0; /* position of start of write */
1387 *bp++ = 0;
1388 *bp++ = 0; /* size of write */
1389 *bp++ = 0;
1390 *bp++ = htonl(attr->ia_size >> 32); /* new file length */
1391 *bp++ = htonl((u32) attr->ia_size);
1392
David Howells56ff9c82017-01-05 10:38:36 +00001393 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001394}
1395
David Howells31143d52007-05-09 02:33:46 -07001396/*
1397 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
1398 * so as to alter the file size also
1399 */
1400static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
1401 struct afs_vnode *vnode, struct iattr *attr,
David Howells56ff9c82017-01-05 10:38:36 +00001402 bool async)
David Howells31143d52007-05-09 02:33:46 -07001403{
1404 struct afs_call *call;
1405 __be32 *bp;
1406
1407 _enter(",%x,{%x:%u},,",
1408 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1409
1410 ASSERT(attr->ia_valid & ATTR_SIZE);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001411 if (attr->ia_size >> 32)
1412 return afs_fs_setattr_size64(server, key, vnode, attr,
David Howells56ff9c82017-01-05 10:38:36 +00001413 async);
David Howells31143d52007-05-09 02:33:46 -07001414
1415 call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
1416 (4 + 6 + 3) * 4,
1417 (21 + 6) * 4);
1418 if (!call)
1419 return -ENOMEM;
1420
1421 call->key = key;
1422 call->reply = vnode;
1423 call->service_id = FS_SERVICE;
1424 call->port = htons(AFS_FS_PORT);
1425 call->store_version = vnode->status.data_version + 1;
1426 call->operation_ID = FSSTOREDATA;
1427
1428 /* marshall the parameters */
1429 bp = call->request;
1430 *bp++ = htonl(FSSTOREDATA);
1431 *bp++ = htonl(vnode->fid.vid);
1432 *bp++ = htonl(vnode->fid.vnode);
1433 *bp++ = htonl(vnode->fid.unique);
1434
1435 xdr_encode_AFS_StoreStatus(&bp, attr);
1436
1437 *bp++ = 0; /* position of start of write */
1438 *bp++ = 0; /* size of write */
1439 *bp++ = htonl(attr->ia_size); /* new file length */
1440
David Howells56ff9c82017-01-05 10:38:36 +00001441 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells31143d52007-05-09 02:33:46 -07001442}
1443
1444/*
1445 * set the attributes on a file, using FS.StoreData if there's a change in file
1446 * size, and FS.StoreStatus otherwise
1447 */
1448int afs_fs_setattr(struct afs_server *server, struct key *key,
1449 struct afs_vnode *vnode, struct iattr *attr,
David Howells56ff9c82017-01-05 10:38:36 +00001450 bool async)
David Howells31143d52007-05-09 02:33:46 -07001451{
1452 struct afs_call *call;
1453 __be32 *bp;
1454
1455 if (attr->ia_valid & ATTR_SIZE)
1456 return afs_fs_setattr_size(server, key, vnode, attr,
David Howells56ff9c82017-01-05 10:38:36 +00001457 async);
David Howells31143d52007-05-09 02:33:46 -07001458
1459 _enter(",%x,{%x:%u},,",
1460 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1461
1462 call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
1463 (4 + 6) * 4,
1464 (21 + 6) * 4);
1465 if (!call)
1466 return -ENOMEM;
1467
1468 call->key = key;
1469 call->reply = vnode;
1470 call->service_id = FS_SERVICE;
1471 call->port = htons(AFS_FS_PORT);
1472 call->operation_ID = FSSTORESTATUS;
1473
1474 /* marshall the parameters */
1475 bp = call->request;
1476 *bp++ = htonl(FSSTORESTATUS);
1477 *bp++ = htonl(vnode->fid.vid);
1478 *bp++ = htonl(vnode->fid.vnode);
1479 *bp++ = htonl(vnode->fid.unique);
1480
1481 xdr_encode_AFS_StoreStatus(&bp, attr);
1482
David Howells56ff9c82017-01-05 10:38:36 +00001483 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells31143d52007-05-09 02:33:46 -07001484}
David Howells45222b92007-05-10 22:22:20 -07001485
1486/*
1487 * deliver reply data to an FS.GetVolumeStatus
1488 */
David Howellsd0016482016-08-30 20:42:14 +01001489static int afs_deliver_fs_get_volume_status(struct afs_call *call)
David Howells45222b92007-05-10 22:22:20 -07001490{
1491 const __be32 *bp;
1492 char *p;
1493 int ret;
1494
David Howellsd0016482016-08-30 20:42:14 +01001495 _enter("{%u}", call->unmarshall);
David Howells45222b92007-05-10 22:22:20 -07001496
1497 switch (call->unmarshall) {
1498 case 0:
1499 call->offset = 0;
1500 call->unmarshall++;
1501
1502 /* extract the returned status record */
1503 case 1:
1504 _debug("extract status");
David Howellsd0016482016-08-30 20:42:14 +01001505 ret = afs_extract_data(call, call->buffer,
1506 12 * 4, true);
David Howells372ee162016-08-03 14:11:40 +01001507 if (ret < 0)
1508 return ret;
David Howells45222b92007-05-10 22:22:20 -07001509
1510 bp = call->buffer;
1511 xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
1512 call->offset = 0;
1513 call->unmarshall++;
1514
1515 /* extract the volume name length */
1516 case 2:
David Howellsd0016482016-08-30 20:42:14 +01001517 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001518 if (ret < 0)
1519 return ret;
David Howells45222b92007-05-10 22:22:20 -07001520
1521 call->count = ntohl(call->tmp);
1522 _debug("volname length: %u", call->count);
1523 if (call->count >= AFSNAMEMAX)
1524 return -EBADMSG;
1525 call->offset = 0;
1526 call->unmarshall++;
1527
1528 /* extract the volume name */
1529 case 3:
1530 _debug("extract volname");
1531 if (call->count > 0) {
David Howellsd0016482016-08-30 20:42:14 +01001532 ret = afs_extract_data(call, call->reply3,
1533 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001534 if (ret < 0)
1535 return ret;
David Howells45222b92007-05-10 22:22:20 -07001536 }
1537
1538 p = call->reply3;
1539 p[call->count] = 0;
1540 _debug("volname '%s'", p);
1541
1542 call->offset = 0;
1543 call->unmarshall++;
1544
1545 /* extract the volume name padding */
1546 if ((call->count & 3) == 0) {
1547 call->unmarshall++;
1548 goto no_volname_padding;
1549 }
1550 call->count = 4 - (call->count & 3);
1551
1552 case 4:
David Howellsd0016482016-08-30 20:42:14 +01001553 ret = afs_extract_data(call, call->buffer,
1554 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001555 if (ret < 0)
1556 return ret;
David Howells45222b92007-05-10 22:22:20 -07001557
1558 call->offset = 0;
1559 call->unmarshall++;
1560 no_volname_padding:
1561
1562 /* extract the offline message length */
1563 case 5:
David Howellsd0016482016-08-30 20:42:14 +01001564 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001565 if (ret < 0)
1566 return ret;
David Howells45222b92007-05-10 22:22:20 -07001567
1568 call->count = ntohl(call->tmp);
1569 _debug("offline msg length: %u", call->count);
1570 if (call->count >= AFSNAMEMAX)
1571 return -EBADMSG;
1572 call->offset = 0;
1573 call->unmarshall++;
1574
1575 /* extract the offline message */
1576 case 6:
1577 _debug("extract offline");
1578 if (call->count > 0) {
David Howellsd0016482016-08-30 20:42:14 +01001579 ret = afs_extract_data(call, call->reply3,
1580 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001581 if (ret < 0)
1582 return ret;
David Howells45222b92007-05-10 22:22:20 -07001583 }
1584
1585 p = call->reply3;
1586 p[call->count] = 0;
1587 _debug("offline '%s'", p);
1588
1589 call->offset = 0;
1590 call->unmarshall++;
1591
1592 /* extract the offline message padding */
1593 if ((call->count & 3) == 0) {
1594 call->unmarshall++;
1595 goto no_offline_padding;
1596 }
1597 call->count = 4 - (call->count & 3);
1598
1599 case 7:
David Howellsd0016482016-08-30 20:42:14 +01001600 ret = afs_extract_data(call, call->buffer,
1601 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001602 if (ret < 0)
1603 return ret;
David Howells45222b92007-05-10 22:22:20 -07001604
1605 call->offset = 0;
1606 call->unmarshall++;
1607 no_offline_padding:
1608
1609 /* extract the message of the day length */
1610 case 8:
David Howellsd0016482016-08-30 20:42:14 +01001611 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001612 if (ret < 0)
1613 return ret;
David Howells45222b92007-05-10 22:22:20 -07001614
1615 call->count = ntohl(call->tmp);
1616 _debug("motd length: %u", call->count);
1617 if (call->count >= AFSNAMEMAX)
1618 return -EBADMSG;
1619 call->offset = 0;
1620 call->unmarshall++;
1621
1622 /* extract the message of the day */
1623 case 9:
1624 _debug("extract motd");
1625 if (call->count > 0) {
David Howellsd0016482016-08-30 20:42:14 +01001626 ret = afs_extract_data(call, call->reply3,
1627 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001628 if (ret < 0)
1629 return ret;
David Howells45222b92007-05-10 22:22:20 -07001630 }
1631
1632 p = call->reply3;
1633 p[call->count] = 0;
1634 _debug("motd '%s'", p);
1635
1636 call->offset = 0;
1637 call->unmarshall++;
1638
1639 /* extract the message of the day padding */
David Howellsd0016482016-08-30 20:42:14 +01001640 call->count = (4 - (call->count & 3)) & 3;
David Howells45222b92007-05-10 22:22:20 -07001641
1642 case 10:
David Howellsd0016482016-08-30 20:42:14 +01001643 ret = afs_extract_data(call, call->buffer,
1644 call->count, false);
David Howells372ee162016-08-03 14:11:40 +01001645 if (ret < 0)
1646 return ret;
David Howells45222b92007-05-10 22:22:20 -07001647
1648 call->offset = 0;
1649 call->unmarshall++;
David Howells45222b92007-05-10 22:22:20 -07001650 case 11:
David Howells45222b92007-05-10 22:22:20 -07001651 break;
1652 }
1653
David Howells45222b92007-05-10 22:22:20 -07001654 _leave(" = 0 [done]");
1655 return 0;
1656}
1657
1658/*
1659 * destroy an FS.GetVolumeStatus call
1660 */
1661static void afs_get_volume_status_call_destructor(struct afs_call *call)
1662{
1663 kfree(call->reply3);
1664 call->reply3 = NULL;
1665 afs_flat_call_destructor(call);
1666}
1667
1668/*
1669 * FS.GetVolumeStatus operation type
1670 */
1671static const struct afs_call_type afs_RXFSGetVolumeStatus = {
1672 .name = "FS.GetVolumeStatus",
1673 .deliver = afs_deliver_fs_get_volume_status,
1674 .abort_to_error = afs_abort_to_error,
1675 .destructor = afs_get_volume_status_call_destructor,
1676};
1677
1678/*
1679 * fetch the status of a volume
1680 */
1681int afs_fs_get_volume_status(struct afs_server *server,
1682 struct key *key,
1683 struct afs_vnode *vnode,
1684 struct afs_volume_status *vs,
David Howells56ff9c82017-01-05 10:38:36 +00001685 bool async)
David Howells45222b92007-05-10 22:22:20 -07001686{
1687 struct afs_call *call;
1688 __be32 *bp;
1689 void *tmpbuf;
1690
1691 _enter("");
1692
1693 tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
1694 if (!tmpbuf)
1695 return -ENOMEM;
1696
1697 call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
1698 if (!call) {
1699 kfree(tmpbuf);
1700 return -ENOMEM;
1701 }
1702
1703 call->key = key;
1704 call->reply = vnode;
1705 call->reply2 = vs;
1706 call->reply3 = tmpbuf;
1707 call->service_id = FS_SERVICE;
1708 call->port = htons(AFS_FS_PORT);
1709
1710 /* marshall the parameters */
1711 bp = call->request;
1712 bp[0] = htonl(FSGETVOLUMESTATUS);
1713 bp[1] = htonl(vnode->fid.vid);
1714
David Howells56ff9c82017-01-05 10:38:36 +00001715 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells45222b92007-05-10 22:22:20 -07001716}
David Howellse8d6c552007-07-15 23:40:12 -07001717
1718/*
1719 * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1720 */
David Howellsd0016482016-08-30 20:42:14 +01001721static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
David Howellse8d6c552007-07-15 23:40:12 -07001722{
1723 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001724 int ret;
David Howellse8d6c552007-07-15 23:40:12 -07001725
David Howellsd0016482016-08-30 20:42:14 +01001726 _enter("{%u}", call->unmarshall);
David Howellse8d6c552007-07-15 23:40:12 -07001727
David Howellsd0016482016-08-30 20:42:14 +01001728 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001729 if (ret < 0)
1730 return ret;
David Howellse8d6c552007-07-15 23:40:12 -07001731
1732 /* unmarshall the reply once we've received all of it */
1733 bp = call->buffer;
1734 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1735
1736 _leave(" = 0 [done]");
1737 return 0;
1738}
1739
1740/*
1741 * FS.SetLock operation type
1742 */
1743static const struct afs_call_type afs_RXFSSetLock = {
1744 .name = "FS.SetLock",
1745 .deliver = afs_deliver_fs_xxxx_lock,
1746 .abort_to_error = afs_abort_to_error,
1747 .destructor = afs_flat_call_destructor,
1748};
1749
1750/*
1751 * FS.ExtendLock operation type
1752 */
1753static const struct afs_call_type afs_RXFSExtendLock = {
1754 .name = "FS.ExtendLock",
1755 .deliver = afs_deliver_fs_xxxx_lock,
1756 .abort_to_error = afs_abort_to_error,
1757 .destructor = afs_flat_call_destructor,
1758};
1759
1760/*
1761 * FS.ReleaseLock operation type
1762 */
1763static const struct afs_call_type afs_RXFSReleaseLock = {
1764 .name = "FS.ReleaseLock",
1765 .deliver = afs_deliver_fs_xxxx_lock,
1766 .abort_to_error = afs_abort_to_error,
1767 .destructor = afs_flat_call_destructor,
1768};
1769
1770/*
1771 * get a lock on a file
1772 */
1773int afs_fs_set_lock(struct afs_server *server,
1774 struct key *key,
1775 struct afs_vnode *vnode,
1776 afs_lock_type_t type,
David Howells56ff9c82017-01-05 10:38:36 +00001777 bool async)
David Howellse8d6c552007-07-15 23:40:12 -07001778{
1779 struct afs_call *call;
1780 __be32 *bp;
1781
1782 _enter("");
1783
1784 call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4);
1785 if (!call)
1786 return -ENOMEM;
1787
1788 call->key = key;
1789 call->reply = vnode;
1790 call->service_id = FS_SERVICE;
1791 call->port = htons(AFS_FS_PORT);
1792
1793 /* marshall the parameters */
1794 bp = call->request;
1795 *bp++ = htonl(FSSETLOCK);
1796 *bp++ = htonl(vnode->fid.vid);
1797 *bp++ = htonl(vnode->fid.vnode);
1798 *bp++ = htonl(vnode->fid.unique);
1799 *bp++ = htonl(type);
1800
David Howells56ff9c82017-01-05 10:38:36 +00001801 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellse8d6c552007-07-15 23:40:12 -07001802}
1803
1804/*
1805 * extend a lock on a file
1806 */
1807int afs_fs_extend_lock(struct afs_server *server,
1808 struct key *key,
1809 struct afs_vnode *vnode,
David Howells56ff9c82017-01-05 10:38:36 +00001810 bool async)
David Howellse8d6c552007-07-15 23:40:12 -07001811{
1812 struct afs_call *call;
1813 __be32 *bp;
1814
1815 _enter("");
1816
1817 call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4);
1818 if (!call)
1819 return -ENOMEM;
1820
1821 call->key = key;
1822 call->reply = vnode;
1823 call->service_id = FS_SERVICE;
1824 call->port = htons(AFS_FS_PORT);
1825
1826 /* marshall the parameters */
1827 bp = call->request;
1828 *bp++ = htonl(FSEXTENDLOCK);
1829 *bp++ = htonl(vnode->fid.vid);
1830 *bp++ = htonl(vnode->fid.vnode);
1831 *bp++ = htonl(vnode->fid.unique);
1832
David Howells56ff9c82017-01-05 10:38:36 +00001833 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellse8d6c552007-07-15 23:40:12 -07001834}
1835
1836/*
1837 * release a lock on a file
1838 */
1839int afs_fs_release_lock(struct afs_server *server,
1840 struct key *key,
1841 struct afs_vnode *vnode,
David Howells56ff9c82017-01-05 10:38:36 +00001842 bool async)
David Howellse8d6c552007-07-15 23:40:12 -07001843{
1844 struct afs_call *call;
1845 __be32 *bp;
1846
1847 _enter("");
1848
1849 call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1850 if (!call)
1851 return -ENOMEM;
1852
1853 call->key = key;
1854 call->reply = vnode;
1855 call->service_id = FS_SERVICE;
1856 call->port = htons(AFS_FS_PORT);
1857
1858 /* marshall the parameters */
1859 bp = call->request;
1860 *bp++ = htonl(FSRELEASELOCK);
1861 *bp++ = htonl(vnode->fid.vid);
1862 *bp++ = htonl(vnode->fid.vnode);
1863 *bp++ = htonl(vnode->fid.unique);
1864
David Howells56ff9c82017-01-05 10:38:36 +00001865 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellse8d6c552007-07-15 23:40:12 -07001866}