blob: 6f917dd1238c0662ac23f95be87ceb65b2a58786 [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++;
David Howellse8e581a2017-03-16 16:27:44 +0000396 if (req->index >= req->nr_pages) {
397 call->unmarshall = 4;
David Howells6db3ac32017-03-16 16:27:44 +0000398 goto begin_discard;
David Howellse8e581a2017-03-16 16:27:44 +0000399 }
David Howells196ee9c2017-01-05 10:38:34 +0000400 goto begin_page;
401 }
David Howells08e0e7c2007-04-26 15:55:03 -0700402 }
David Howells6db3ac32017-03-16 16:27:44 +0000403 goto no_more_data;
404
405 /* Discard any excess data the server gave us */
406 begin_discard:
407 case 4:
408 size = min_t(size_t, sizeof(afs_discard_buffer), req->remain);
409 call->count = size;
410 _debug("extract discard %u/%llu %zu/%u",
411 req->remain, req->actual_len, call->offset, call->count);
412
413 call->offset = 0;
414 ret = afs_extract_data(call, afs_discard_buffer, call->count, true);
415 req->remain -= call->offset;
416 if (ret < 0)
417 return ret;
418 if (req->remain > 0)
419 goto begin_discard;
David Howells08e0e7c2007-04-26 15:55:03 -0700420
David Howells196ee9c2017-01-05 10:38:34 +0000421 no_more_data:
David Howells08e0e7c2007-04-26 15:55:03 -0700422 call->offset = 0;
David Howells6db3ac32017-03-16 16:27:44 +0000423 call->unmarshall = 5;
David Howells08e0e7c2007-04-26 15:55:03 -0700424
425 /* extract the metadata */
David Howells6db3ac32017-03-16 16:27:44 +0000426 case 5:
David Howellsd0016482016-08-30 20:42:14 +0100427 ret = afs_extract_data(call, call->buffer,
428 (21 + 3 + 6) * 4, false);
David Howells372ee162016-08-03 14:11:40 +0100429 if (ret < 0)
430 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700431
432 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700433 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700434 xdr_decode_AFSCallBack(&bp, vnode);
David Howells08e0e7c2007-04-26 15:55:03 -0700435 if (call->reply2)
436 xdr_decode_AFSVolSync(&bp, call->reply2);
437
438 call->offset = 0;
439 call->unmarshall++;
440
David Howells6db3ac32017-03-16 16:27:44 +0000441 case 6:
David Howells08e0e7c2007-04-26 15:55:03 -0700442 break;
443 }
444
David Howells6db3ac32017-03-16 16:27:44 +0000445 for (; req->index < req->nr_pages; req->index++) {
446 if (call->count < PAGE_SIZE)
447 zero_user_segment(req->pages[req->index],
448 call->count, PAGE_SIZE);
David Howells196ee9c2017-01-05 10:38:34 +0000449 if (req->page_done)
450 req->page_done(call, req);
David Howells6db3ac32017-03-16 16:27:44 +0000451 call->count = 0;
David Howells416351f2007-05-09 02:33:45 -0700452 }
453
David Howells08e0e7c2007-04-26 15:55:03 -0700454 _leave(" = 0 [done]");
455 return 0;
456}
457
David Howells196ee9c2017-01-05 10:38:34 +0000458static void afs_fetch_data_destructor(struct afs_call *call)
459{
460 struct afs_read *req = call->reply3;
461
462 afs_put_read(req);
463 afs_flat_call_destructor(call);
464}
465
David Howells08e0e7c2007-04-26 15:55:03 -0700466/*
467 * FS.FetchData operation type
468 */
469static const struct afs_call_type afs_RXFSFetchData = {
David Howells00d3b7a2007-04-26 15:57:07 -0700470 .name = "FS.FetchData",
David Howells08e0e7c2007-04-26 15:55:03 -0700471 .deliver = afs_deliver_fs_fetch_data,
472 .abort_to_error = afs_abort_to_error,
David Howells196ee9c2017-01-05 10:38:34 +0000473 .destructor = afs_fetch_data_destructor,
David Howells08e0e7c2007-04-26 15:55:03 -0700474};
475
David Howellsb9b1f8d2007-05-10 03:15:21 -0700476static const struct afs_call_type afs_RXFSFetchData64 = {
477 .name = "FS.FetchData64",
478 .deliver = afs_deliver_fs_fetch_data,
479 .abort_to_error = afs_abort_to_error,
David Howells196ee9c2017-01-05 10:38:34 +0000480 .destructor = afs_fetch_data_destructor,
David Howellsb9b1f8d2007-05-10 03:15:21 -0700481};
482
483/*
484 * fetch data from a very large file
485 */
486static int afs_fs_fetch_data64(struct afs_server *server,
487 struct key *key,
488 struct afs_vnode *vnode,
David Howells196ee9c2017-01-05 10:38:34 +0000489 struct afs_read *req,
David Howells56ff9c82017-01-05 10:38:36 +0000490 bool async)
David Howellsb9b1f8d2007-05-10 03:15:21 -0700491{
492 struct afs_call *call;
493 __be32 *bp;
494
495 _enter("");
496
David Howellsb9b1f8d2007-05-10 03:15:21 -0700497 call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
498 if (!call)
499 return -ENOMEM;
500
501 call->key = key;
502 call->reply = vnode;
503 call->reply2 = NULL; /* volsync */
David Howells196ee9c2017-01-05 10:38:34 +0000504 call->reply3 = req;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700505 call->service_id = FS_SERVICE;
506 call->port = htons(AFS_FS_PORT);
507 call->operation_ID = FSFETCHDATA64;
508
509 /* marshall the parameters */
510 bp = call->request;
511 bp[0] = htonl(FSFETCHDATA64);
512 bp[1] = htonl(vnode->fid.vid);
513 bp[2] = htonl(vnode->fid.vnode);
514 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000515 bp[4] = htonl(upper_32_bits(req->pos));
516 bp[5] = htonl(lower_32_bits(req->pos));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700517 bp[6] = 0;
David Howells196ee9c2017-01-05 10:38:34 +0000518 bp[7] = htonl(lower_32_bits(req->len));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700519
David Howells196ee9c2017-01-05 10:38:34 +0000520 atomic_inc(&req->usage);
David Howells56ff9c82017-01-05 10:38:36 +0000521 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700522}
523
David Howells08e0e7c2007-04-26 15:55:03 -0700524/*
525 * fetch data from a file
526 */
527int afs_fs_fetch_data(struct afs_server *server,
David Howells00d3b7a2007-04-26 15:57:07 -0700528 struct key *key,
David Howells08e0e7c2007-04-26 15:55:03 -0700529 struct afs_vnode *vnode,
David Howells196ee9c2017-01-05 10:38:34 +0000530 struct afs_read *req,
David Howells56ff9c82017-01-05 10:38:36 +0000531 bool async)
David Howells08e0e7c2007-04-26 15:55:03 -0700532{
533 struct afs_call *call;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 __be32 *bp;
535
David Howells196ee9c2017-01-05 10:38:34 +0000536 if (upper_32_bits(req->pos) ||
537 upper_32_bits(req->len) ||
538 upper_32_bits(req->pos + req->len))
David Howells56ff9c82017-01-05 10:38:36 +0000539 return afs_fs_fetch_data64(server, key, vnode, req, async);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700540
David Howells08e0e7c2007-04-26 15:55:03 -0700541 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
David Howells260a9802007-04-26 15:59:35 -0700543 call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700544 if (!call)
545 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
David Howells00d3b7a2007-04-26 15:57:07 -0700547 call->key = key;
David Howells08e0e7c2007-04-26 15:55:03 -0700548 call->reply = vnode;
David Howells260a9802007-04-26 15:59:35 -0700549 call->reply2 = NULL; /* volsync */
David Howells196ee9c2017-01-05 10:38:34 +0000550 call->reply3 = req;
David Howells08e0e7c2007-04-26 15:55:03 -0700551 call->service_id = FS_SERVICE;
552 call->port = htons(AFS_FS_PORT);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700553 call->operation_ID = FSFETCHDATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700556 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 bp[0] = htonl(FSFETCHDATA);
David Howells08e0e7c2007-04-26 15:55:03 -0700558 bp[1] = htonl(vnode->fid.vid);
559 bp[2] = htonl(vnode->fid.vnode);
560 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000561 bp[4] = htonl(lower_32_bits(req->pos));
562 bp[5] = htonl(lower_32_bits(req->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
David Howells196ee9c2017-01-05 10:38:34 +0000564 atomic_inc(&req->usage);
David Howells56ff9c82017-01-05 10:38:36 +0000565 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsec268152007-04-26 15:49:28 -0700566}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568/*
David Howells08e0e7c2007-04-26 15:55:03 -0700569 * deliver reply data to an FS.GiveUpCallBacks
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 */
David Howellsd0016482016-08-30 20:42:14 +0100571static int afs_deliver_fs_give_up_callbacks(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572{
David Howellsd0016482016-08-30 20:42:14 +0100573 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
David Howells372ee162016-08-03 14:11:40 +0100575 /* shouldn't be any reply data */
David Howellsd0016482016-08-30 20:42:14 +0100576 return afs_extract_data(call, NULL, 0, false);
David Howells08e0e7c2007-04-26 15:55:03 -0700577}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
David Howells08e0e7c2007-04-26 15:55:03 -0700579/*
580 * FS.GiveUpCallBacks operation type
581 */
582static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
David Howells00d3b7a2007-04-26 15:57:07 -0700583 .name = "FS.GiveUpCallBacks",
David Howells08e0e7c2007-04-26 15:55:03 -0700584 .deliver = afs_deliver_fs_give_up_callbacks,
585 .abort_to_error = afs_abort_to_error,
586 .destructor = afs_flat_call_destructor,
587};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
David Howells08e0e7c2007-04-26 15:55:03 -0700589/*
590 * give up a set of callbacks
591 * - the callbacks are held in the server->cb_break ring
592 */
593int afs_fs_give_up_callbacks(struct afs_server *server,
David Howells56ff9c82017-01-05 10:38:36 +0000594 bool async)
David Howells08e0e7c2007-04-26 15:55:03 -0700595{
596 struct afs_call *call;
597 size_t ncallbacks;
598 __be32 *bp, *tp;
599 int loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
David Howells08e0e7c2007-04-26 15:55:03 -0700601 ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
602 ARRAY_SIZE(server->cb_break));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
David Howells08e0e7c2007-04-26 15:55:03 -0700604 _enter("{%zu},", ncallbacks);
605
606 if (ncallbacks == 0)
607 return 0;
608 if (ncallbacks > AFSCBMAX)
609 ncallbacks = AFSCBMAX;
610
611 _debug("break %zu callbacks", ncallbacks);
612
613 call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
614 12 + ncallbacks * 6 * 4, 0);
615 if (!call)
616 return -ENOMEM;
617
618 call->service_id = FS_SERVICE;
619 call->port = htons(AFS_FS_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700622 bp = call->request;
623 tp = bp + 2 + ncallbacks * 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 *bp++ = htonl(FSGIVEUPCALLBACKS);
David Howells08e0e7c2007-04-26 15:55:03 -0700625 *bp++ = htonl(ncallbacks);
626 *tp++ = htonl(ncallbacks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
David Howells08e0e7c2007-04-26 15:55:03 -0700628 atomic_sub(ncallbacks, &server->cb_break_n);
629 for (loop = ncallbacks; loop > 0; loop--) {
630 struct afs_callback *cb =
631 &server->cb_break[server->cb_break_tail];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
David Howells08e0e7c2007-04-26 15:55:03 -0700633 *bp++ = htonl(cb->fid.vid);
634 *bp++ = htonl(cb->fid.vnode);
635 *bp++ = htonl(cb->fid.unique);
636 *tp++ = htonl(cb->version);
637 *tp++ = htonl(cb->expiry);
638 *tp++ = htonl(cb->type);
639 smp_mb();
640 server->cb_break_tail =
641 (server->cb_break_tail + 1) &
642 (ARRAY_SIZE(server->cb_break) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644
David Howells08e0e7c2007-04-26 15:55:03 -0700645 ASSERT(ncallbacks > 0);
646 wake_up_nr(&server->cb_break_waitq, ncallbacks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
David Howells56ff9c82017-01-05 10:38:36 +0000648 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsec268152007-04-26 15:49:28 -0700649}
David Howells260a9802007-04-26 15:59:35 -0700650
651/*
652 * deliver reply data to an FS.CreateFile or an FS.MakeDir
653 */
David Howellsd0016482016-08-30 20:42:14 +0100654static int afs_deliver_fs_create_vnode(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700655{
656 struct afs_vnode *vnode = call->reply;
657 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100658 int ret;
David Howells260a9802007-04-26 15:59:35 -0700659
David Howellsd0016482016-08-30 20:42:14 +0100660 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700661
David Howellsd0016482016-08-30 20:42:14 +0100662 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100663 if (ret < 0)
664 return ret;
David Howells260a9802007-04-26 15:59:35 -0700665
666 /* unmarshall the reply once we've received all of it */
667 bp = call->buffer;
668 xdr_decode_AFSFid(&bp, call->reply2);
David Howells31143d52007-05-09 02:33:46 -0700669 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
670 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700671 xdr_decode_AFSCallBack_raw(&bp, call->reply4);
672 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
673
674 _leave(" = 0 [done]");
675 return 0;
676}
677
678/*
679 * FS.CreateFile and FS.MakeDir operation type
680 */
681static const struct afs_call_type afs_RXFSCreateXXXX = {
682 .name = "FS.CreateXXXX",
683 .deliver = afs_deliver_fs_create_vnode,
684 .abort_to_error = afs_abort_to_error,
685 .destructor = afs_flat_call_destructor,
686};
687
688/*
689 * create a file or make a directory
690 */
691int afs_fs_create(struct afs_server *server,
692 struct key *key,
693 struct afs_vnode *vnode,
694 const char *name,
695 umode_t mode,
696 struct afs_fid *newfid,
697 struct afs_file_status *newstatus,
698 struct afs_callback *newcb,
David Howells56ff9c82017-01-05 10:38:36 +0000699 bool async)
David Howells260a9802007-04-26 15:59:35 -0700700{
701 struct afs_call *call;
702 size_t namesz, reqsz, padsz;
703 __be32 *bp;
704
705 _enter("");
706
707 namesz = strlen(name);
708 padsz = (4 - (namesz & 3)) & 3;
709 reqsz = (5 * 4) + namesz + padsz + (6 * 4);
710
711 call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
712 (3 + 21 + 21 + 3 + 6) * 4);
713 if (!call)
714 return -ENOMEM;
715
716 call->key = key;
717 call->reply = vnode;
718 call->reply2 = newfid;
719 call->reply3 = newstatus;
720 call->reply4 = newcb;
721 call->service_id = FS_SERVICE;
722 call->port = htons(AFS_FS_PORT);
723
724 /* marshall the parameters */
725 bp = call->request;
726 *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
727 *bp++ = htonl(vnode->fid.vid);
728 *bp++ = htonl(vnode->fid.vnode);
729 *bp++ = htonl(vnode->fid.unique);
730 *bp++ = htonl(namesz);
731 memcpy(bp, name, namesz);
732 bp = (void *) bp + namesz;
733 if (padsz > 0) {
734 memset(bp, 0, padsz);
735 bp = (void *) bp + padsz;
736 }
737 *bp++ = htonl(AFS_SET_MODE);
738 *bp++ = 0; /* mtime */
739 *bp++ = 0; /* owner */
740 *bp++ = 0; /* group */
741 *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
742 *bp++ = 0; /* segment size */
743
David Howells56ff9c82017-01-05 10:38:36 +0000744 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -0700745}
746
747/*
748 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
749 */
David Howellsd0016482016-08-30 20:42:14 +0100750static int afs_deliver_fs_remove(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700751{
752 struct afs_vnode *vnode = call->reply;
753 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100754 int ret;
David Howells260a9802007-04-26 15:59:35 -0700755
David Howellsd0016482016-08-30 20:42:14 +0100756 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700757
David Howellsd0016482016-08-30 20:42:14 +0100758 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100759 if (ret < 0)
760 return ret;
David Howells260a9802007-04-26 15:59:35 -0700761
762 /* unmarshall the reply once we've received all of it */
763 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700764 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700765 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
766
767 _leave(" = 0 [done]");
768 return 0;
769}
770
771/*
772 * FS.RemoveDir/FS.RemoveFile operation type
773 */
774static const struct afs_call_type afs_RXFSRemoveXXXX = {
775 .name = "FS.RemoveXXXX",
776 .deliver = afs_deliver_fs_remove,
777 .abort_to_error = afs_abort_to_error,
778 .destructor = afs_flat_call_destructor,
779};
780
781/*
782 * remove a file or directory
783 */
784int afs_fs_remove(struct afs_server *server,
785 struct key *key,
786 struct afs_vnode *vnode,
787 const char *name,
788 bool isdir,
David Howells56ff9c82017-01-05 10:38:36 +0000789 bool async)
David Howells260a9802007-04-26 15:59:35 -0700790{
791 struct afs_call *call;
792 size_t namesz, reqsz, padsz;
793 __be32 *bp;
794
795 _enter("");
796
797 namesz = strlen(name);
798 padsz = (4 - (namesz & 3)) & 3;
799 reqsz = (5 * 4) + namesz + padsz;
800
801 call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
802 if (!call)
803 return -ENOMEM;
804
805 call->key = key;
806 call->reply = vnode;
807 call->service_id = FS_SERVICE;
808 call->port = htons(AFS_FS_PORT);
809
810 /* marshall the parameters */
811 bp = call->request;
812 *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
813 *bp++ = htonl(vnode->fid.vid);
814 *bp++ = htonl(vnode->fid.vnode);
815 *bp++ = htonl(vnode->fid.unique);
816 *bp++ = htonl(namesz);
817 memcpy(bp, name, namesz);
818 bp = (void *) bp + namesz;
819 if (padsz > 0) {
820 memset(bp, 0, padsz);
821 bp = (void *) bp + padsz;
822 }
823
David Howells56ff9c82017-01-05 10:38:36 +0000824 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -0700825}
826
827/*
828 * deliver reply data to an FS.Link
829 */
David Howellsd0016482016-08-30 20:42:14 +0100830static int afs_deliver_fs_link(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700831{
832 struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
833 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100834 int ret;
David Howells260a9802007-04-26 15:59:35 -0700835
David Howellsd0016482016-08-30 20:42:14 +0100836 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700837
David Howellsd0016482016-08-30 20:42:14 +0100838 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100839 if (ret < 0)
840 return ret;
David Howells260a9802007-04-26 15:59:35 -0700841
842 /* unmarshall the reply once we've received all of it */
843 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700844 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
845 xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700846 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
847
848 _leave(" = 0 [done]");
849 return 0;
850}
851
852/*
853 * FS.Link operation type
854 */
855static const struct afs_call_type afs_RXFSLink = {
856 .name = "FS.Link",
857 .deliver = afs_deliver_fs_link,
858 .abort_to_error = afs_abort_to_error,
859 .destructor = afs_flat_call_destructor,
860};
861
862/*
863 * make a hard link
864 */
865int afs_fs_link(struct afs_server *server,
866 struct key *key,
867 struct afs_vnode *dvnode,
868 struct afs_vnode *vnode,
869 const char *name,
David Howells56ff9c82017-01-05 10:38:36 +0000870 bool async)
David Howells260a9802007-04-26 15:59:35 -0700871{
872 struct afs_call *call;
873 size_t namesz, reqsz, padsz;
874 __be32 *bp;
875
876 _enter("");
877
878 namesz = strlen(name);
879 padsz = (4 - (namesz & 3)) & 3;
880 reqsz = (5 * 4) + namesz + padsz + (3 * 4);
881
882 call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
883 if (!call)
884 return -ENOMEM;
885
886 call->key = key;
887 call->reply = dvnode;
888 call->reply2 = vnode;
889 call->service_id = FS_SERVICE;
890 call->port = htons(AFS_FS_PORT);
891
892 /* marshall the parameters */
893 bp = call->request;
894 *bp++ = htonl(FSLINK);
895 *bp++ = htonl(dvnode->fid.vid);
896 *bp++ = htonl(dvnode->fid.vnode);
897 *bp++ = htonl(dvnode->fid.unique);
898 *bp++ = htonl(namesz);
899 memcpy(bp, name, namesz);
900 bp = (void *) bp + namesz;
901 if (padsz > 0) {
902 memset(bp, 0, padsz);
903 bp = (void *) bp + padsz;
904 }
905 *bp++ = htonl(vnode->fid.vid);
906 *bp++ = htonl(vnode->fid.vnode);
907 *bp++ = htonl(vnode->fid.unique);
908
David Howells56ff9c82017-01-05 10:38:36 +0000909 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -0700910}
911
912/*
913 * deliver reply data to an FS.Symlink
914 */
David Howellsd0016482016-08-30 20:42:14 +0100915static int afs_deliver_fs_symlink(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700916{
917 struct afs_vnode *vnode = call->reply;
918 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100919 int ret;
David Howells260a9802007-04-26 15:59:35 -0700920
David Howellsd0016482016-08-30 20:42:14 +0100921 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700922
David Howellsd0016482016-08-30 20:42:14 +0100923 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100924 if (ret < 0)
925 return ret;
David Howells260a9802007-04-26 15:59:35 -0700926
927 /* unmarshall the reply once we've received all of it */
928 bp = call->buffer;
929 xdr_decode_AFSFid(&bp, call->reply2);
David Howells31143d52007-05-09 02:33:46 -0700930 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
931 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700932 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
933
934 _leave(" = 0 [done]");
935 return 0;
936}
937
938/*
939 * FS.Symlink operation type
940 */
941static const struct afs_call_type afs_RXFSSymlink = {
942 .name = "FS.Symlink",
943 .deliver = afs_deliver_fs_symlink,
944 .abort_to_error = afs_abort_to_error,
945 .destructor = afs_flat_call_destructor,
946};
947
948/*
949 * create a symbolic link
950 */
951int afs_fs_symlink(struct afs_server *server,
952 struct key *key,
953 struct afs_vnode *vnode,
954 const char *name,
955 const char *contents,
956 struct afs_fid *newfid,
957 struct afs_file_status *newstatus,
David Howells56ff9c82017-01-05 10:38:36 +0000958 bool async)
David Howells260a9802007-04-26 15:59:35 -0700959{
960 struct afs_call *call;
961 size_t namesz, reqsz, padsz, c_namesz, c_padsz;
962 __be32 *bp;
963
964 _enter("");
965
966 namesz = strlen(name);
967 padsz = (4 - (namesz & 3)) & 3;
968
969 c_namesz = strlen(contents);
970 c_padsz = (4 - (c_namesz & 3)) & 3;
971
972 reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
973
974 call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
975 (3 + 21 + 21 + 6) * 4);
976 if (!call)
977 return -ENOMEM;
978
979 call->key = key;
980 call->reply = vnode;
981 call->reply2 = newfid;
982 call->reply3 = newstatus;
983 call->service_id = FS_SERVICE;
984 call->port = htons(AFS_FS_PORT);
985
986 /* marshall the parameters */
987 bp = call->request;
988 *bp++ = htonl(FSSYMLINK);
989 *bp++ = htonl(vnode->fid.vid);
990 *bp++ = htonl(vnode->fid.vnode);
991 *bp++ = htonl(vnode->fid.unique);
992 *bp++ = htonl(namesz);
993 memcpy(bp, name, namesz);
994 bp = (void *) bp + namesz;
995 if (padsz > 0) {
996 memset(bp, 0, padsz);
997 bp = (void *) bp + padsz;
998 }
999 *bp++ = htonl(c_namesz);
1000 memcpy(bp, contents, c_namesz);
1001 bp = (void *) bp + c_namesz;
1002 if (c_padsz > 0) {
1003 memset(bp, 0, c_padsz);
1004 bp = (void *) bp + c_padsz;
1005 }
1006 *bp++ = htonl(AFS_SET_MODE);
1007 *bp++ = 0; /* mtime */
1008 *bp++ = 0; /* owner */
1009 *bp++ = 0; /* group */
1010 *bp++ = htonl(S_IRWXUGO); /* unix mode */
1011 *bp++ = 0; /* segment size */
1012
David Howells56ff9c82017-01-05 10:38:36 +00001013 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -07001014}
1015
1016/*
1017 * deliver reply data to an FS.Rename
1018 */
David Howellsd0016482016-08-30 20:42:14 +01001019static int afs_deliver_fs_rename(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -07001020{
1021 struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
1022 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001023 int ret;
David Howells260a9802007-04-26 15:59:35 -07001024
David Howellsd0016482016-08-30 20:42:14 +01001025 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -07001026
David Howellsd0016482016-08-30 20:42:14 +01001027 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001028 if (ret < 0)
1029 return ret;
David Howells260a9802007-04-26 15:59:35 -07001030
1031 /* unmarshall the reply once we've received all of it */
1032 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -07001033 xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
David Howells260a9802007-04-26 15:59:35 -07001034 if (new_dvnode != orig_dvnode)
David Howells31143d52007-05-09 02:33:46 -07001035 xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
1036 NULL);
David Howells260a9802007-04-26 15:59:35 -07001037 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1038
1039 _leave(" = 0 [done]");
1040 return 0;
1041}
1042
1043/*
1044 * FS.Rename operation type
1045 */
1046static const struct afs_call_type afs_RXFSRename = {
1047 .name = "FS.Rename",
1048 .deliver = afs_deliver_fs_rename,
1049 .abort_to_error = afs_abort_to_error,
1050 .destructor = afs_flat_call_destructor,
1051};
1052
1053/*
1054 * create a symbolic link
1055 */
1056int afs_fs_rename(struct afs_server *server,
1057 struct key *key,
1058 struct afs_vnode *orig_dvnode,
1059 const char *orig_name,
1060 struct afs_vnode *new_dvnode,
1061 const char *new_name,
David Howells56ff9c82017-01-05 10:38:36 +00001062 bool async)
David Howells260a9802007-04-26 15:59:35 -07001063{
1064 struct afs_call *call;
1065 size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1066 __be32 *bp;
1067
1068 _enter("");
1069
1070 o_namesz = strlen(orig_name);
1071 o_padsz = (4 - (o_namesz & 3)) & 3;
1072
1073 n_namesz = strlen(new_name);
1074 n_padsz = (4 - (n_namesz & 3)) & 3;
1075
1076 reqsz = (4 * 4) +
1077 4 + o_namesz + o_padsz +
1078 (3 * 4) +
1079 4 + n_namesz + n_padsz;
1080
1081 call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1082 if (!call)
1083 return -ENOMEM;
1084
1085 call->key = key;
1086 call->reply = orig_dvnode;
1087 call->reply2 = new_dvnode;
1088 call->service_id = FS_SERVICE;
1089 call->port = htons(AFS_FS_PORT);
1090
1091 /* marshall the parameters */
1092 bp = call->request;
1093 *bp++ = htonl(FSRENAME);
1094 *bp++ = htonl(orig_dvnode->fid.vid);
1095 *bp++ = htonl(orig_dvnode->fid.vnode);
1096 *bp++ = htonl(orig_dvnode->fid.unique);
1097 *bp++ = htonl(o_namesz);
1098 memcpy(bp, orig_name, o_namesz);
1099 bp = (void *) bp + o_namesz;
1100 if (o_padsz > 0) {
1101 memset(bp, 0, o_padsz);
1102 bp = (void *) bp + o_padsz;
1103 }
1104
1105 *bp++ = htonl(new_dvnode->fid.vid);
1106 *bp++ = htonl(new_dvnode->fid.vnode);
1107 *bp++ = htonl(new_dvnode->fid.unique);
1108 *bp++ = htonl(n_namesz);
1109 memcpy(bp, new_name, n_namesz);
1110 bp = (void *) bp + n_namesz;
1111 if (n_padsz > 0) {
1112 memset(bp, 0, n_padsz);
1113 bp = (void *) bp + n_padsz;
1114 }
1115
David Howells56ff9c82017-01-05 10:38:36 +00001116 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells260a9802007-04-26 15:59:35 -07001117}
David Howells31143d52007-05-09 02:33:46 -07001118
1119/*
1120 * deliver reply data to an FS.StoreData
1121 */
David Howellsd0016482016-08-30 20:42:14 +01001122static int afs_deliver_fs_store_data(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001123{
1124 struct afs_vnode *vnode = call->reply;
1125 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001126 int ret;
David Howells31143d52007-05-09 02:33:46 -07001127
David Howellsd0016482016-08-30 20:42:14 +01001128 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001129
David Howellsd0016482016-08-30 20:42:14 +01001130 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001131 if (ret < 0)
1132 return ret;
David Howells31143d52007-05-09 02:33:46 -07001133
1134 /* unmarshall the reply once we've received all of it */
1135 bp = call->buffer;
1136 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
1137 &call->store_version);
1138 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1139
1140 afs_pages_written_back(vnode, call);
1141
1142 _leave(" = 0 [done]");
1143 return 0;
1144}
1145
1146/*
1147 * FS.StoreData operation type
1148 */
1149static const struct afs_call_type afs_RXFSStoreData = {
1150 .name = "FS.StoreData",
1151 .deliver = afs_deliver_fs_store_data,
1152 .abort_to_error = afs_abort_to_error,
1153 .destructor = afs_flat_call_destructor,
1154};
1155
David Howellsb9b1f8d2007-05-10 03:15:21 -07001156static const struct afs_call_type afs_RXFSStoreData64 = {
1157 .name = "FS.StoreData64",
1158 .deliver = afs_deliver_fs_store_data,
1159 .abort_to_error = afs_abort_to_error,
1160 .destructor = afs_flat_call_destructor,
1161};
1162
1163/*
1164 * store a set of pages to a very large file
1165 */
1166static int afs_fs_store_data64(struct afs_server *server,
1167 struct afs_writeback *wb,
1168 pgoff_t first, pgoff_t last,
1169 unsigned offset, unsigned to,
1170 loff_t size, loff_t pos, loff_t i_size,
David Howells56ff9c82017-01-05 10:38:36 +00001171 bool async)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001172{
1173 struct afs_vnode *vnode = wb->vnode;
1174 struct afs_call *call;
1175 __be32 *bp;
1176
1177 _enter(",%x,{%x:%u},,",
1178 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1179
1180 call = afs_alloc_flat_call(&afs_RXFSStoreData64,
1181 (4 + 6 + 3 * 2) * 4,
1182 (21 + 6) * 4);
1183 if (!call)
1184 return -ENOMEM;
1185
1186 call->wb = wb;
1187 call->key = wb->key;
1188 call->reply = vnode;
1189 call->service_id = FS_SERVICE;
1190 call->port = htons(AFS_FS_PORT);
1191 call->mapping = vnode->vfs_inode.i_mapping;
1192 call->first = first;
1193 call->last = last;
1194 call->first_offset = offset;
1195 call->last_to = to;
1196 call->send_pages = true;
1197 call->store_version = vnode->status.data_version + 1;
1198
1199 /* marshall the parameters */
1200 bp = call->request;
1201 *bp++ = htonl(FSSTOREDATA64);
1202 *bp++ = htonl(vnode->fid.vid);
1203 *bp++ = htonl(vnode->fid.vnode);
1204 *bp++ = htonl(vnode->fid.unique);
1205
1206 *bp++ = 0; /* mask */
1207 *bp++ = 0; /* mtime */
1208 *bp++ = 0; /* owner */
1209 *bp++ = 0; /* group */
1210 *bp++ = 0; /* unix mode */
1211 *bp++ = 0; /* segment size */
1212
1213 *bp++ = htonl(pos >> 32);
1214 *bp++ = htonl((u32) pos);
1215 *bp++ = htonl(size >> 32);
1216 *bp++ = htonl((u32) size);
1217 *bp++ = htonl(i_size >> 32);
1218 *bp++ = htonl((u32) i_size);
1219
David Howells56ff9c82017-01-05 10:38:36 +00001220 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001221}
1222
David Howells31143d52007-05-09 02:33:46 -07001223/*
1224 * store a set of pages
1225 */
1226int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
1227 pgoff_t first, pgoff_t last,
1228 unsigned offset, unsigned to,
David Howells56ff9c82017-01-05 10:38:36 +00001229 bool async)
David Howells31143d52007-05-09 02:33:46 -07001230{
1231 struct afs_vnode *vnode = wb->vnode;
1232 struct afs_call *call;
1233 loff_t size, pos, i_size;
1234 __be32 *bp;
1235
1236 _enter(",%x,{%x:%u},,",
1237 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1238
1239 size = to - offset;
1240 if (first != last)
1241 size += (loff_t)(last - first) << PAGE_SHIFT;
1242 pos = (loff_t)first << PAGE_SHIFT;
1243 pos += offset;
1244
1245 i_size = i_size_read(&vnode->vfs_inode);
1246 if (pos + size > i_size)
1247 i_size = size + pos;
1248
1249 _debug("size %llx, at %llx, i_size %llx",
1250 (unsigned long long) size, (unsigned long long) pos,
1251 (unsigned long long) i_size);
1252
David Howellsb9b1f8d2007-05-10 03:15:21 -07001253 if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
1254 return afs_fs_store_data64(server, wb, first, last, offset, to,
David Howells56ff9c82017-01-05 10:38:36 +00001255 size, pos, i_size, async);
David Howells31143d52007-05-09 02:33:46 -07001256
1257 call = afs_alloc_flat_call(&afs_RXFSStoreData,
1258 (4 + 6 + 3) * 4,
1259 (21 + 6) * 4);
1260 if (!call)
1261 return -ENOMEM;
1262
1263 call->wb = wb;
1264 call->key = wb->key;
1265 call->reply = vnode;
1266 call->service_id = FS_SERVICE;
1267 call->port = htons(AFS_FS_PORT);
1268 call->mapping = vnode->vfs_inode.i_mapping;
1269 call->first = first;
1270 call->last = last;
1271 call->first_offset = offset;
1272 call->last_to = to;
1273 call->send_pages = true;
1274 call->store_version = vnode->status.data_version + 1;
1275
1276 /* marshall the parameters */
1277 bp = call->request;
1278 *bp++ = htonl(FSSTOREDATA);
1279 *bp++ = htonl(vnode->fid.vid);
1280 *bp++ = htonl(vnode->fid.vnode);
1281 *bp++ = htonl(vnode->fid.unique);
1282
1283 *bp++ = 0; /* mask */
1284 *bp++ = 0; /* mtime */
1285 *bp++ = 0; /* owner */
1286 *bp++ = 0; /* group */
1287 *bp++ = 0; /* unix mode */
1288 *bp++ = 0; /* segment size */
1289
1290 *bp++ = htonl(pos);
1291 *bp++ = htonl(size);
1292 *bp++ = htonl(i_size);
1293
David Howells56ff9c82017-01-05 10:38:36 +00001294 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells31143d52007-05-09 02:33:46 -07001295}
1296
1297/*
1298 * deliver reply data to an FS.StoreStatus
1299 */
David Howellsd0016482016-08-30 20:42:14 +01001300static int afs_deliver_fs_store_status(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001301{
1302 afs_dataversion_t *store_version;
1303 struct afs_vnode *vnode = call->reply;
1304 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001305 int ret;
David Howells31143d52007-05-09 02:33:46 -07001306
David Howellsd0016482016-08-30 20:42:14 +01001307 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001308
David Howellsd0016482016-08-30 20:42:14 +01001309 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001310 if (ret < 0)
1311 return ret;
David Howells31143d52007-05-09 02:33:46 -07001312
1313 /* unmarshall the reply once we've received all of it */
1314 store_version = NULL;
1315 if (call->operation_ID == FSSTOREDATA)
1316 store_version = &call->store_version;
1317
1318 bp = call->buffer;
1319 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
1320 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1321
1322 _leave(" = 0 [done]");
1323 return 0;
1324}
1325
1326/*
1327 * FS.StoreStatus operation type
1328 */
1329static const struct afs_call_type afs_RXFSStoreStatus = {
1330 .name = "FS.StoreStatus",
1331 .deliver = afs_deliver_fs_store_status,
1332 .abort_to_error = afs_abort_to_error,
1333 .destructor = afs_flat_call_destructor,
1334};
1335
1336static const struct afs_call_type afs_RXFSStoreData_as_Status = {
1337 .name = "FS.StoreData",
1338 .deliver = afs_deliver_fs_store_status,
1339 .abort_to_error = afs_abort_to_error,
1340 .destructor = afs_flat_call_destructor,
1341};
1342
David Howellsb9b1f8d2007-05-10 03:15:21 -07001343static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1344 .name = "FS.StoreData64",
1345 .deliver = afs_deliver_fs_store_status,
1346 .abort_to_error = afs_abort_to_error,
1347 .destructor = afs_flat_call_destructor,
1348};
1349
1350/*
1351 * set the attributes on a very large file, using FS.StoreData rather than
1352 * FS.StoreStatus so as to alter the file size also
1353 */
1354static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
1355 struct afs_vnode *vnode, struct iattr *attr,
David Howells56ff9c82017-01-05 10:38:36 +00001356 bool async)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001357{
1358 struct afs_call *call;
1359 __be32 *bp;
1360
1361 _enter(",%x,{%x:%u},,",
1362 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1363
1364 ASSERT(attr->ia_valid & ATTR_SIZE);
1365
1366 call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
1367 (4 + 6 + 3 * 2) * 4,
1368 (21 + 6) * 4);
1369 if (!call)
1370 return -ENOMEM;
1371
1372 call->key = key;
1373 call->reply = vnode;
1374 call->service_id = FS_SERVICE;
1375 call->port = htons(AFS_FS_PORT);
1376 call->store_version = vnode->status.data_version + 1;
1377 call->operation_ID = FSSTOREDATA;
1378
1379 /* marshall the parameters */
1380 bp = call->request;
1381 *bp++ = htonl(FSSTOREDATA64);
1382 *bp++ = htonl(vnode->fid.vid);
1383 *bp++ = htonl(vnode->fid.vnode);
1384 *bp++ = htonl(vnode->fid.unique);
1385
1386 xdr_encode_AFS_StoreStatus(&bp, attr);
1387
1388 *bp++ = 0; /* position of start of write */
1389 *bp++ = 0;
1390 *bp++ = 0; /* size of write */
1391 *bp++ = 0;
1392 *bp++ = htonl(attr->ia_size >> 32); /* new file length */
1393 *bp++ = htonl((u32) attr->ia_size);
1394
David Howells56ff9c82017-01-05 10:38:36 +00001395 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001396}
1397
David Howells31143d52007-05-09 02:33:46 -07001398/*
1399 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
1400 * so as to alter the file size also
1401 */
1402static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
1403 struct afs_vnode *vnode, struct iattr *attr,
David Howells56ff9c82017-01-05 10:38:36 +00001404 bool async)
David Howells31143d52007-05-09 02:33:46 -07001405{
1406 struct afs_call *call;
1407 __be32 *bp;
1408
1409 _enter(",%x,{%x:%u},,",
1410 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1411
1412 ASSERT(attr->ia_valid & ATTR_SIZE);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001413 if (attr->ia_size >> 32)
1414 return afs_fs_setattr_size64(server, key, vnode, attr,
David Howells56ff9c82017-01-05 10:38:36 +00001415 async);
David Howells31143d52007-05-09 02:33:46 -07001416
1417 call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
1418 (4 + 6 + 3) * 4,
1419 (21 + 6) * 4);
1420 if (!call)
1421 return -ENOMEM;
1422
1423 call->key = key;
1424 call->reply = vnode;
1425 call->service_id = FS_SERVICE;
1426 call->port = htons(AFS_FS_PORT);
1427 call->store_version = vnode->status.data_version + 1;
1428 call->operation_ID = FSSTOREDATA;
1429
1430 /* marshall the parameters */
1431 bp = call->request;
1432 *bp++ = htonl(FSSTOREDATA);
1433 *bp++ = htonl(vnode->fid.vid);
1434 *bp++ = htonl(vnode->fid.vnode);
1435 *bp++ = htonl(vnode->fid.unique);
1436
1437 xdr_encode_AFS_StoreStatus(&bp, attr);
1438
1439 *bp++ = 0; /* position of start of write */
1440 *bp++ = 0; /* size of write */
1441 *bp++ = htonl(attr->ia_size); /* new file length */
1442
David Howells56ff9c82017-01-05 10:38:36 +00001443 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells31143d52007-05-09 02:33:46 -07001444}
1445
1446/*
1447 * set the attributes on a file, using FS.StoreData if there's a change in file
1448 * size, and FS.StoreStatus otherwise
1449 */
1450int afs_fs_setattr(struct afs_server *server, struct key *key,
1451 struct afs_vnode *vnode, struct iattr *attr,
David Howells56ff9c82017-01-05 10:38:36 +00001452 bool async)
David Howells31143d52007-05-09 02:33:46 -07001453{
1454 struct afs_call *call;
1455 __be32 *bp;
1456
1457 if (attr->ia_valid & ATTR_SIZE)
1458 return afs_fs_setattr_size(server, key, vnode, attr,
David Howells56ff9c82017-01-05 10:38:36 +00001459 async);
David Howells31143d52007-05-09 02:33:46 -07001460
1461 _enter(",%x,{%x:%u},,",
1462 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1463
1464 call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
1465 (4 + 6) * 4,
1466 (21 + 6) * 4);
1467 if (!call)
1468 return -ENOMEM;
1469
1470 call->key = key;
1471 call->reply = vnode;
1472 call->service_id = FS_SERVICE;
1473 call->port = htons(AFS_FS_PORT);
1474 call->operation_ID = FSSTORESTATUS;
1475
1476 /* marshall the parameters */
1477 bp = call->request;
1478 *bp++ = htonl(FSSTORESTATUS);
1479 *bp++ = htonl(vnode->fid.vid);
1480 *bp++ = htonl(vnode->fid.vnode);
1481 *bp++ = htonl(vnode->fid.unique);
1482
1483 xdr_encode_AFS_StoreStatus(&bp, attr);
1484
David Howells56ff9c82017-01-05 10:38:36 +00001485 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells31143d52007-05-09 02:33:46 -07001486}
David Howells45222b92007-05-10 22:22:20 -07001487
1488/*
1489 * deliver reply data to an FS.GetVolumeStatus
1490 */
David Howellsd0016482016-08-30 20:42:14 +01001491static int afs_deliver_fs_get_volume_status(struct afs_call *call)
David Howells45222b92007-05-10 22:22:20 -07001492{
1493 const __be32 *bp;
1494 char *p;
1495 int ret;
1496
David Howellsd0016482016-08-30 20:42:14 +01001497 _enter("{%u}", call->unmarshall);
David Howells45222b92007-05-10 22:22:20 -07001498
1499 switch (call->unmarshall) {
1500 case 0:
1501 call->offset = 0;
1502 call->unmarshall++;
1503
1504 /* extract the returned status record */
1505 case 1:
1506 _debug("extract status");
David Howellsd0016482016-08-30 20:42:14 +01001507 ret = afs_extract_data(call, call->buffer,
1508 12 * 4, true);
David Howells372ee162016-08-03 14:11:40 +01001509 if (ret < 0)
1510 return ret;
David Howells45222b92007-05-10 22:22:20 -07001511
1512 bp = call->buffer;
1513 xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
1514 call->offset = 0;
1515 call->unmarshall++;
1516
1517 /* extract the volume name length */
1518 case 2:
David Howellsd0016482016-08-30 20:42:14 +01001519 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001520 if (ret < 0)
1521 return ret;
David Howells45222b92007-05-10 22:22:20 -07001522
1523 call->count = ntohl(call->tmp);
1524 _debug("volname length: %u", call->count);
1525 if (call->count >= AFSNAMEMAX)
1526 return -EBADMSG;
1527 call->offset = 0;
1528 call->unmarshall++;
1529
1530 /* extract the volume name */
1531 case 3:
1532 _debug("extract volname");
1533 if (call->count > 0) {
David Howellsd0016482016-08-30 20:42:14 +01001534 ret = afs_extract_data(call, call->reply3,
1535 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001536 if (ret < 0)
1537 return ret;
David Howells45222b92007-05-10 22:22:20 -07001538 }
1539
1540 p = call->reply3;
1541 p[call->count] = 0;
1542 _debug("volname '%s'", p);
1543
1544 call->offset = 0;
1545 call->unmarshall++;
1546
1547 /* extract the volume name padding */
1548 if ((call->count & 3) == 0) {
1549 call->unmarshall++;
1550 goto no_volname_padding;
1551 }
1552 call->count = 4 - (call->count & 3);
1553
1554 case 4:
David Howellsd0016482016-08-30 20:42:14 +01001555 ret = afs_extract_data(call, call->buffer,
1556 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001557 if (ret < 0)
1558 return ret;
David Howells45222b92007-05-10 22:22:20 -07001559
1560 call->offset = 0;
1561 call->unmarshall++;
1562 no_volname_padding:
1563
1564 /* extract the offline message length */
1565 case 5:
David Howellsd0016482016-08-30 20:42:14 +01001566 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001567 if (ret < 0)
1568 return ret;
David Howells45222b92007-05-10 22:22:20 -07001569
1570 call->count = ntohl(call->tmp);
1571 _debug("offline msg length: %u", call->count);
1572 if (call->count >= AFSNAMEMAX)
1573 return -EBADMSG;
1574 call->offset = 0;
1575 call->unmarshall++;
1576
1577 /* extract the offline message */
1578 case 6:
1579 _debug("extract offline");
1580 if (call->count > 0) {
David Howellsd0016482016-08-30 20:42:14 +01001581 ret = afs_extract_data(call, call->reply3,
1582 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001583 if (ret < 0)
1584 return ret;
David Howells45222b92007-05-10 22:22:20 -07001585 }
1586
1587 p = call->reply3;
1588 p[call->count] = 0;
1589 _debug("offline '%s'", p);
1590
1591 call->offset = 0;
1592 call->unmarshall++;
1593
1594 /* extract the offline message padding */
1595 if ((call->count & 3) == 0) {
1596 call->unmarshall++;
1597 goto no_offline_padding;
1598 }
1599 call->count = 4 - (call->count & 3);
1600
1601 case 7:
David Howellsd0016482016-08-30 20:42:14 +01001602 ret = afs_extract_data(call, call->buffer,
1603 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001604 if (ret < 0)
1605 return ret;
David Howells45222b92007-05-10 22:22:20 -07001606
1607 call->offset = 0;
1608 call->unmarshall++;
1609 no_offline_padding:
1610
1611 /* extract the message of the day length */
1612 case 8:
David Howellsd0016482016-08-30 20:42:14 +01001613 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001614 if (ret < 0)
1615 return ret;
David Howells45222b92007-05-10 22:22:20 -07001616
1617 call->count = ntohl(call->tmp);
1618 _debug("motd length: %u", call->count);
1619 if (call->count >= AFSNAMEMAX)
1620 return -EBADMSG;
1621 call->offset = 0;
1622 call->unmarshall++;
1623
1624 /* extract the message of the day */
1625 case 9:
1626 _debug("extract motd");
1627 if (call->count > 0) {
David Howellsd0016482016-08-30 20:42:14 +01001628 ret = afs_extract_data(call, call->reply3,
1629 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001630 if (ret < 0)
1631 return ret;
David Howells45222b92007-05-10 22:22:20 -07001632 }
1633
1634 p = call->reply3;
1635 p[call->count] = 0;
1636 _debug("motd '%s'", p);
1637
1638 call->offset = 0;
1639 call->unmarshall++;
1640
1641 /* extract the message of the day padding */
David Howellsd0016482016-08-30 20:42:14 +01001642 call->count = (4 - (call->count & 3)) & 3;
David Howells45222b92007-05-10 22:22:20 -07001643
1644 case 10:
David Howellsd0016482016-08-30 20:42:14 +01001645 ret = afs_extract_data(call, call->buffer,
1646 call->count, false);
David Howells372ee162016-08-03 14:11:40 +01001647 if (ret < 0)
1648 return ret;
David Howells45222b92007-05-10 22:22:20 -07001649
1650 call->offset = 0;
1651 call->unmarshall++;
David Howells45222b92007-05-10 22:22:20 -07001652 case 11:
David Howells45222b92007-05-10 22:22:20 -07001653 break;
1654 }
1655
David Howells45222b92007-05-10 22:22:20 -07001656 _leave(" = 0 [done]");
1657 return 0;
1658}
1659
1660/*
1661 * destroy an FS.GetVolumeStatus call
1662 */
1663static void afs_get_volume_status_call_destructor(struct afs_call *call)
1664{
1665 kfree(call->reply3);
1666 call->reply3 = NULL;
1667 afs_flat_call_destructor(call);
1668}
1669
1670/*
1671 * FS.GetVolumeStatus operation type
1672 */
1673static const struct afs_call_type afs_RXFSGetVolumeStatus = {
1674 .name = "FS.GetVolumeStatus",
1675 .deliver = afs_deliver_fs_get_volume_status,
1676 .abort_to_error = afs_abort_to_error,
1677 .destructor = afs_get_volume_status_call_destructor,
1678};
1679
1680/*
1681 * fetch the status of a volume
1682 */
1683int afs_fs_get_volume_status(struct afs_server *server,
1684 struct key *key,
1685 struct afs_vnode *vnode,
1686 struct afs_volume_status *vs,
David Howells56ff9c82017-01-05 10:38:36 +00001687 bool async)
David Howells45222b92007-05-10 22:22:20 -07001688{
1689 struct afs_call *call;
1690 __be32 *bp;
1691 void *tmpbuf;
1692
1693 _enter("");
1694
1695 tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
1696 if (!tmpbuf)
1697 return -ENOMEM;
1698
1699 call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
1700 if (!call) {
1701 kfree(tmpbuf);
1702 return -ENOMEM;
1703 }
1704
1705 call->key = key;
1706 call->reply = vnode;
1707 call->reply2 = vs;
1708 call->reply3 = tmpbuf;
1709 call->service_id = FS_SERVICE;
1710 call->port = htons(AFS_FS_PORT);
1711
1712 /* marshall the parameters */
1713 bp = call->request;
1714 bp[0] = htonl(FSGETVOLUMESTATUS);
1715 bp[1] = htonl(vnode->fid.vid);
1716
David Howells56ff9c82017-01-05 10:38:36 +00001717 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howells45222b92007-05-10 22:22:20 -07001718}
David Howellse8d6c552007-07-15 23:40:12 -07001719
1720/*
1721 * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1722 */
David Howellsd0016482016-08-30 20:42:14 +01001723static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
David Howellse8d6c552007-07-15 23:40:12 -07001724{
1725 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001726 int ret;
David Howellse8d6c552007-07-15 23:40:12 -07001727
David Howellsd0016482016-08-30 20:42:14 +01001728 _enter("{%u}", call->unmarshall);
David Howellse8d6c552007-07-15 23:40:12 -07001729
David Howellsd0016482016-08-30 20:42:14 +01001730 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001731 if (ret < 0)
1732 return ret;
David Howellse8d6c552007-07-15 23:40:12 -07001733
1734 /* unmarshall the reply once we've received all of it */
1735 bp = call->buffer;
1736 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1737
1738 _leave(" = 0 [done]");
1739 return 0;
1740}
1741
1742/*
1743 * FS.SetLock operation type
1744 */
1745static const struct afs_call_type afs_RXFSSetLock = {
1746 .name = "FS.SetLock",
1747 .deliver = afs_deliver_fs_xxxx_lock,
1748 .abort_to_error = afs_abort_to_error,
1749 .destructor = afs_flat_call_destructor,
1750};
1751
1752/*
1753 * FS.ExtendLock operation type
1754 */
1755static const struct afs_call_type afs_RXFSExtendLock = {
1756 .name = "FS.ExtendLock",
1757 .deliver = afs_deliver_fs_xxxx_lock,
1758 .abort_to_error = afs_abort_to_error,
1759 .destructor = afs_flat_call_destructor,
1760};
1761
1762/*
1763 * FS.ReleaseLock operation type
1764 */
1765static const struct afs_call_type afs_RXFSReleaseLock = {
1766 .name = "FS.ReleaseLock",
1767 .deliver = afs_deliver_fs_xxxx_lock,
1768 .abort_to_error = afs_abort_to_error,
1769 .destructor = afs_flat_call_destructor,
1770};
1771
1772/*
1773 * get a lock on a file
1774 */
1775int afs_fs_set_lock(struct afs_server *server,
1776 struct key *key,
1777 struct afs_vnode *vnode,
1778 afs_lock_type_t type,
David Howells56ff9c82017-01-05 10:38:36 +00001779 bool async)
David Howellse8d6c552007-07-15 23:40:12 -07001780{
1781 struct afs_call *call;
1782 __be32 *bp;
1783
1784 _enter("");
1785
1786 call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4);
1787 if (!call)
1788 return -ENOMEM;
1789
1790 call->key = key;
1791 call->reply = vnode;
1792 call->service_id = FS_SERVICE;
1793 call->port = htons(AFS_FS_PORT);
1794
1795 /* marshall the parameters */
1796 bp = call->request;
1797 *bp++ = htonl(FSSETLOCK);
1798 *bp++ = htonl(vnode->fid.vid);
1799 *bp++ = htonl(vnode->fid.vnode);
1800 *bp++ = htonl(vnode->fid.unique);
1801 *bp++ = htonl(type);
1802
David Howells56ff9c82017-01-05 10:38:36 +00001803 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellse8d6c552007-07-15 23:40:12 -07001804}
1805
1806/*
1807 * extend a lock on a file
1808 */
1809int afs_fs_extend_lock(struct afs_server *server,
1810 struct key *key,
1811 struct afs_vnode *vnode,
David Howells56ff9c82017-01-05 10:38:36 +00001812 bool async)
David Howellse8d6c552007-07-15 23:40:12 -07001813{
1814 struct afs_call *call;
1815 __be32 *bp;
1816
1817 _enter("");
1818
1819 call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4);
1820 if (!call)
1821 return -ENOMEM;
1822
1823 call->key = key;
1824 call->reply = vnode;
1825 call->service_id = FS_SERVICE;
1826 call->port = htons(AFS_FS_PORT);
1827
1828 /* marshall the parameters */
1829 bp = call->request;
1830 *bp++ = htonl(FSEXTENDLOCK);
1831 *bp++ = htonl(vnode->fid.vid);
1832 *bp++ = htonl(vnode->fid.vnode);
1833 *bp++ = htonl(vnode->fid.unique);
1834
David Howells56ff9c82017-01-05 10:38:36 +00001835 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellse8d6c552007-07-15 23:40:12 -07001836}
1837
1838/*
1839 * release a lock on a file
1840 */
1841int afs_fs_release_lock(struct afs_server *server,
1842 struct key *key,
1843 struct afs_vnode *vnode,
David Howells56ff9c82017-01-05 10:38:36 +00001844 bool async)
David Howellse8d6c552007-07-15 23:40:12 -07001845{
1846 struct afs_call *call;
1847 __be32 *bp;
1848
1849 _enter("");
1850
1851 call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1852 if (!call)
1853 return -ENOMEM;
1854
1855 call->key = key;
1856 call->reply = vnode;
1857 call->service_id = FS_SERVICE;
1858 call->port = htons(AFS_FS_PORT);
1859
1860 /* marshall the parameters */
1861 bp = call->request;
1862 *bp++ = htonl(FSRELEASELOCK);
1863 *bp++ = htonl(vnode->fid.vid);
1864 *bp++ = htonl(vnode->fid.vnode);
1865 *bp++ = htonl(vnode->fid.unique);
1866
David Howells56ff9c82017-01-05 10:38:36 +00001867 return afs_make_call(&server->addr, call, GFP_NOFS, async);
David Howellse8d6c552007-07-15 23:40:12 -07001868}