blob: 72ff3679fa2a81d7deb094d00e7fcc66aa8b0977 [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
David Howellsd2ddc772017-11-02 15:27:50 +000025static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi)
David Howellsc435ee32017-11-02 15:27:49 +000026{
David Howellsd2ddc772017-11-02 15:27:50 +000027 call->cbi = afs_get_cb_interest(cbi);
David Howellsc435ee32017-11-02 15:27:49 +000028}
29
David Howells6db3ac32017-03-16 16:27:44 +000030/*
David Howells260a9802007-04-26 15:59:35 -070031 * decode an AFSFid block
32 */
33static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
34{
35 const __be32 *bp = *_bp;
36
37 fid->vid = ntohl(*bp++);
38 fid->vnode = ntohl(*bp++);
39 fid->unique = ntohl(*bp++);
40 *_bp = bp;
41}
42
43/*
David Howells08e0e7c2007-04-26 15:55:03 -070044 * decode an AFSFetchStatus block
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 */
David Howells08e0e7c2007-04-26 15:55:03 -070046static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
David Howells260a9802007-04-26 15:59:35 -070047 struct afs_file_status *status,
David Howells31143d52007-05-09 02:33:46 -070048 struct afs_vnode *vnode,
49 afs_dataversion_t *store_version)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
David Howells31143d52007-05-09 02:33:46 -070051 afs_dataversion_t expected_version;
David Howells08e0e7c2007-04-26 15:55:03 -070052 const __be32 *bp = *_bp;
53 umode_t mode;
David Howells260a9802007-04-26 15:59:35 -070054 u64 data_version, size;
David Howellsc435ee32017-11-02 15:27:49 +000055 bool changed = false;
Eric W. Biedermana0a53862012-02-07 16:20:48 -080056 kuid_t owner;
57 kgid_t group;
David Howells08e0e7c2007-04-26 15:55:03 -070058
David Howellsd2ddc772017-11-02 15:27:50 +000059 if (vnode)
60 write_seqlock(&vnode->cb_lock);
David Howellsc435ee32017-11-02 15:27:49 +000061
David Howells08e0e7c2007-04-26 15:55:03 -070062#define EXTRACT(DST) \
63 do { \
64 u32 x = ntohl(*bp++); \
David Howellsc435ee32017-11-02 15:27:49 +000065 if (DST != x) \
66 changed |= true; \
David Howells08e0e7c2007-04-26 15:55:03 -070067 DST = x; \
68 } while (0)
69
David Howells260a9802007-04-26 15:59:35 -070070 status->if_version = ntohl(*bp++);
71 EXTRACT(status->type);
72 EXTRACT(status->nlink);
73 size = ntohl(*bp++);
David Howells08e0e7c2007-04-26 15:55:03 -070074 data_version = ntohl(*bp++);
David Howells260a9802007-04-26 15:59:35 -070075 EXTRACT(status->author);
Eric W. Biedermana0a53862012-02-07 16:20:48 -080076 owner = make_kuid(&init_user_ns, ntohl(*bp++));
77 changed |= !uid_eq(owner, status->owner);
78 status->owner = owner;
David Howells260a9802007-04-26 15:59:35 -070079 EXTRACT(status->caller_access); /* call ticket dependent */
80 EXTRACT(status->anon_access);
81 EXTRACT(status->mode);
David Howellsbe080a62017-11-02 15:27:49 +000082 bp++; /* parent.vnode */
83 bp++; /* parent.unique */
David Howells08e0e7c2007-04-26 15:55:03 -070084 bp++; /* seg size */
David Howells260a9802007-04-26 15:59:35 -070085 status->mtime_client = ntohl(*bp++);
86 status->mtime_server = ntohl(*bp++);
Eric W. Biedermana0a53862012-02-07 16:20:48 -080087 group = make_kgid(&init_user_ns, ntohl(*bp++));
88 changed |= !gid_eq(group, status->group);
89 status->group = group;
David Howells08e0e7c2007-04-26 15:55:03 -070090 bp++; /* sync counter */
91 data_version |= (u64) ntohl(*bp++) << 32;
David Howellse8d6c552007-07-15 23:40:12 -070092 EXTRACT(status->lock_count);
David Howells260a9802007-04-26 15:59:35 -070093 size |= (u64) ntohl(*bp++) << 32;
94 bp++; /* spare 4 */
David Howells08e0e7c2007-04-26 15:55:03 -070095 *_bp = bp;
96
David Howells260a9802007-04-26 15:59:35 -070097 if (size != status->size) {
98 status->size = size;
99 changed |= true;
David Howells08e0e7c2007-04-26 15:55:03 -0700100 }
David Howells260a9802007-04-26 15:59:35 -0700101 status->mode &= S_IALLUGO;
David Howells08e0e7c2007-04-26 15:55:03 -0700102
103 _debug("vnode time %lx, %lx",
David Howells260a9802007-04-26 15:59:35 -0700104 status->mtime_client, status->mtime_server);
David Howells08e0e7c2007-04-26 15:55:03 -0700105
David Howells260a9802007-04-26 15:59:35 -0700106 if (vnode) {
David Howells260a9802007-04-26 15:59:35 -0700107 if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
108 _debug("vnode changed");
109 i_size_write(&vnode->vfs_inode, size);
110 vnode->vfs_inode.i_uid = status->owner;
111 vnode->vfs_inode.i_gid = status->group;
David Howellsd6e43f72011-06-14 00:45:44 +0100112 vnode->vfs_inode.i_generation = vnode->fid.unique;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200113 set_nlink(&vnode->vfs_inode, status->nlink);
David Howells260a9802007-04-26 15:59:35 -0700114
115 mode = vnode->vfs_inode.i_mode;
116 mode &= ~S_IALLUGO;
117 mode |= status->mode;
118 barrier();
119 vnode->vfs_inode.i_mode = mode;
120 }
121
Marc Dionneab94f5d2017-03-16 16:27:47 +0000122 vnode->vfs_inode.i_ctime.tv_sec = status->mtime_client;
David Howells260a9802007-04-26 15:59:35 -0700123 vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime;
124 vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime;
David Howellsd6e43f72011-06-14 00:45:44 +0100125 vnode->vfs_inode.i_version = data_version;
David Howells260a9802007-04-26 15:59:35 -0700126 }
127
David Howells31143d52007-05-09 02:33:46 -0700128 expected_version = status->data_version;
129 if (store_version)
130 expected_version = *store_version;
131
132 if (expected_version != data_version) {
David Howells260a9802007-04-26 15:59:35 -0700133 status->data_version = data_version;
134 if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
135 _debug("vnode modified %llx on {%x:%u}",
David S. Millerba3e0e12007-04-26 16:06:22 -0700136 (unsigned long long) data_version,
137 vnode->fid.vid, vnode->fid.vnode);
David Howellsc435ee32017-11-02 15:27:49 +0000138 set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags);
David Howells260a9802007-04-26 15:59:35 -0700139 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
140 }
David Howells31143d52007-05-09 02:33:46 -0700141 } else if (store_version) {
142 status->data_version = data_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 }
David Howellsc435ee32017-11-02 15:27:49 +0000144
David Howellsd2ddc772017-11-02 15:27:50 +0000145 if (vnode)
146 write_sequnlock(&vnode->cb_lock);
David Howellsec268152007-04-26 15:49:28 -0700147}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149/*
David Howells08e0e7c2007-04-26 15:55:03 -0700150 * decode an AFSCallBack block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 */
David Howellsc435ee32017-11-02 15:27:49 +0000152static void xdr_decode_AFSCallBack(struct afs_call *call,
153 struct afs_vnode *vnode,
154 const __be32 **_bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155{
David Howellsd2ddc772017-11-02 15:27:50 +0000156 struct afs_cb_interest *old, *cbi = call->cbi;
David Howells08e0e7c2007-04-26 15:55:03 -0700157 const __be32 *bp = *_bp;
David Howellsc435ee32017-11-02 15:27:49 +0000158 u32 cb_expiry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
David Howellsc435ee32017-11-02 15:27:49 +0000160 write_seqlock(&vnode->cb_lock);
161
David Howellsd2ddc772017-11-02 15:27:50 +0000162 if (call->cb_break == (vnode->cb_break + cbi->server->cb_s_break)) {
David Howellsc435ee32017-11-02 15:27:49 +0000163 vnode->cb_version = ntohl(*bp++);
164 cb_expiry = ntohl(*bp++);
165 vnode->cb_type = ntohl(*bp++);
166 vnode->cb_expires_at = cb_expiry + ktime_get_real_seconds();
David Howellsd2ddc772017-11-02 15:27:50 +0000167 old = vnode->cb_interest;
168 if (old != call->cbi) {
169 vnode->cb_interest = cbi;
170 cbi = old;
171 }
David Howellsc435ee32017-11-02 15:27:49 +0000172 set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
173 } else {
174 bp += 3;
175 }
176
177 write_sequnlock(&vnode->cb_lock);
David Howellsd2ddc772017-11-02 15:27:50 +0000178 call->cbi = cbi;
David Howells08e0e7c2007-04-26 15:55:03 -0700179 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700180}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
David Howells260a9802007-04-26 15:59:35 -0700182static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
183 struct afs_callback *cb)
184{
185 const __be32 *bp = *_bp;
186
187 cb->version = ntohl(*bp++);
188 cb->expiry = ntohl(*bp++);
189 cb->type = ntohl(*bp++);
190 *_bp = bp;
191}
192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193/*
David Howells08e0e7c2007-04-26 15:55:03 -0700194 * decode an AFSVolSync block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 */
David Howells08e0e7c2007-04-26 15:55:03 -0700196static void xdr_decode_AFSVolSync(const __be32 **_bp,
197 struct afs_volsync *volsync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
David Howells08e0e7c2007-04-26 15:55:03 -0700199 const __be32 *bp = *_bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
David Howells08e0e7c2007-04-26 15:55:03 -0700201 volsync->creation = ntohl(*bp++);
202 bp++; /* spare2 */
203 bp++; /* spare3 */
204 bp++; /* spare4 */
205 bp++; /* spare5 */
206 bp++; /* spare6 */
207 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700208}
David Howells08e0e7c2007-04-26 15:55:03 -0700209
210/*
David Howells31143d52007-05-09 02:33:46 -0700211 * encode the requested attributes into an AFSStoreStatus block
212 */
213static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
214{
215 __be32 *bp = *_bp;
216 u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
217
218 mask = 0;
219 if (attr->ia_valid & ATTR_MTIME) {
220 mask |= AFS_SET_MTIME;
221 mtime = attr->ia_mtime.tv_sec;
222 }
223
224 if (attr->ia_valid & ATTR_UID) {
225 mask |= AFS_SET_OWNER;
Eric W. Biedermana0a53862012-02-07 16:20:48 -0800226 owner = from_kuid(&init_user_ns, attr->ia_uid);
David Howells31143d52007-05-09 02:33:46 -0700227 }
228
229 if (attr->ia_valid & ATTR_GID) {
230 mask |= AFS_SET_GROUP;
Eric W. Biedermana0a53862012-02-07 16:20:48 -0800231 group = from_kgid(&init_user_ns, attr->ia_gid);
David Howells31143d52007-05-09 02:33:46 -0700232 }
233
234 if (attr->ia_valid & ATTR_MODE) {
235 mask |= AFS_SET_MODE;
236 mode = attr->ia_mode & S_IALLUGO;
237 }
238
239 *bp++ = htonl(mask);
240 *bp++ = htonl(mtime);
241 *bp++ = htonl(owner);
242 *bp++ = htonl(group);
243 *bp++ = htonl(mode);
244 *bp++ = 0; /* segment size */
245 *_bp = bp;
246}
247
248/*
David Howells45222b92007-05-10 22:22:20 -0700249 * decode an AFSFetchVolumeStatus block
250 */
251static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
252 struct afs_volume_status *vs)
253{
254 const __be32 *bp = *_bp;
255
256 vs->vid = ntohl(*bp++);
257 vs->parent_id = ntohl(*bp++);
258 vs->online = ntohl(*bp++);
259 vs->in_service = ntohl(*bp++);
260 vs->blessed = ntohl(*bp++);
261 vs->needs_salvage = ntohl(*bp++);
262 vs->type = ntohl(*bp++);
263 vs->min_quota = ntohl(*bp++);
264 vs->max_quota = ntohl(*bp++);
265 vs->blocks_in_use = ntohl(*bp++);
266 vs->part_blocks_avail = ntohl(*bp++);
267 vs->part_max_blocks = ntohl(*bp++);
268 *_bp = bp;
269}
270
271/*
David Howells08e0e7c2007-04-26 15:55:03 -0700272 * deliver reply data to an FS.FetchStatus
273 */
David Howellsd0016482016-08-30 20:42:14 +0100274static int afs_deliver_fs_fetch_status(struct afs_call *call)
David Howells08e0e7c2007-04-26 15:55:03 -0700275{
David Howells97e30432017-11-02 15:27:48 +0000276 struct afs_vnode *vnode = call->reply[0];
David Howells08e0e7c2007-04-26 15:55:03 -0700277 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100278 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700279
David Howellsd0016482016-08-30 20:42:14 +0100280 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100281 if (ret < 0)
282 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700283
David Howellsc435ee32017-11-02 15:27:49 +0000284 _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
285
David Howells08e0e7c2007-04-26 15:55:03 -0700286 /* unmarshall the reply once we've received all of it */
287 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700288 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howellsc435ee32017-11-02 15:27:49 +0000289 xdr_decode_AFSCallBack(call, vnode, &bp);
David Howells97e30432017-11-02 15:27:48 +0000290 if (call->reply[1])
291 xdr_decode_AFSVolSync(&bp, call->reply[1]);
David Howells08e0e7c2007-04-26 15:55:03 -0700292
293 _leave(" = 0 [done]");
294 return 0;
295}
296
297/*
298 * FS.FetchStatus operation type
299 */
300static const struct afs_call_type afs_RXFSFetchStatus = {
David Howells00d3b7a2007-04-26 15:57:07 -0700301 .name = "FS.FetchStatus",
David Howells08e0e7c2007-04-26 15:55:03 -0700302 .deliver = afs_deliver_fs_fetch_status,
David Howells08e0e7c2007-04-26 15:55:03 -0700303 .destructor = afs_flat_call_destructor,
304};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306/*
307 * fetch the status information for a file
308 */
David Howellsd2ddc772017-11-02 15:27:50 +0000309int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
David Howellsd2ddc772017-11-02 15:27:50 +0000311 struct afs_vnode *vnode = fc->vnode;
David Howells08e0e7c2007-04-26 15:55:03 -0700312 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000313 struct afs_net *net = afs_v2net(vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 __be32 *bp;
315
David Howells416351f2007-05-09 02:33:45 -0700316 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +0000317 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
David Howellsf044c882017-11-02 15:27:45 +0000319 call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
David Howellsd2ddc772017-11-02 15:27:50 +0000320 if (!call) {
321 fc->ac.error = -ENOMEM;
David Howells08e0e7c2007-04-26 15:55:03 -0700322 return -ENOMEM;
David Howellsd2ddc772017-11-02 15:27:50 +0000323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
David Howellsd2ddc772017-11-02 15:27:50 +0000325 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000326 call->reply[0] = vnode;
327 call->reply[1] = volsync;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700330 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 bp[0] = htonl(FSFETCHSTATUS);
332 bp[1] = htonl(vnode->fid.vid);
333 bp[2] = htonl(vnode->fid.vnode);
334 bp[3] = htonl(vnode->fid.unique);
335
David Howellsd2ddc772017-11-02 15:27:50 +0000336 call->cb_break = fc->cb_break;
337 afs_use_fs_server(call, fc->cbi);
338 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsec268152007-04-26 15:49:28 -0700339}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341/*
David Howells08e0e7c2007-04-26 15:55:03 -0700342 * deliver reply data to an FS.FetchData
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 */
David Howellsd0016482016-08-30 20:42:14 +0100344static int afs_deliver_fs_fetch_data(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
David Howells97e30432017-11-02 15:27:48 +0000346 struct afs_vnode *vnode = call->reply[0];
347 struct afs_read *req = call->reply[2];
David Howells08e0e7c2007-04-26 15:55:03 -0700348 const __be32 *bp;
David Howells196ee9c2017-01-05 10:38:34 +0000349 unsigned int size;
David Howells08e0e7c2007-04-26 15:55:03 -0700350 void *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700352
David Howells6a0e3992017-03-16 16:27:46 +0000353 _enter("{%u,%zu/%u;%llu/%llu}",
David Howells196ee9c2017-01-05 10:38:34 +0000354 call->unmarshall, call->offset, call->count,
355 req->remain, req->actual_len);
David Howells08e0e7c2007-04-26 15:55:03 -0700356
357 switch (call->unmarshall) {
358 case 0:
David Howells196ee9c2017-01-05 10:38:34 +0000359 req->actual_len = 0;
David Howells08e0e7c2007-04-26 15:55:03 -0700360 call->offset = 0;
361 call->unmarshall++;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700362 if (call->operation_ID != FSFETCHDATA64) {
363 call->unmarshall++;
364 goto no_msw;
365 }
David Howells08e0e7c2007-04-26 15:55:03 -0700366
David Howellsb9b1f8d2007-05-10 03:15:21 -0700367 /* extract the upper part of the returned data length of an
368 * FSFETCHDATA64 op (which should always be 0 using this
369 * client) */
David Howells08e0e7c2007-04-26 15:55:03 -0700370 case 1:
David Howellsb9b1f8d2007-05-10 03:15:21 -0700371 _debug("extract data length (MSW)");
David Howellsd0016482016-08-30 20:42:14 +0100372 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +0100373 if (ret < 0)
374 return ret;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700375
David Howells196ee9c2017-01-05 10:38:34 +0000376 req->actual_len = ntohl(call->tmp);
377 req->actual_len <<= 32;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700378 call->offset = 0;
379 call->unmarshall++;
380
381 no_msw:
382 /* extract the returned data length */
383 case 2:
David Howells08e0e7c2007-04-26 15:55:03 -0700384 _debug("extract data length");
David Howellsd0016482016-08-30 20:42:14 +0100385 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +0100386 if (ret < 0)
387 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700388
David Howells196ee9c2017-01-05 10:38:34 +0000389 req->actual_len |= ntohl(call->tmp);
390 _debug("DATA length: %llu", req->actual_len);
David Howells196ee9c2017-01-05 10:38:34 +0000391
392 req->remain = req->actual_len;
393 call->offset = req->pos & (PAGE_SIZE - 1);
394 req->index = 0;
395 if (req->actual_len == 0)
396 goto no_more_data;
David Howells08e0e7c2007-04-26 15:55:03 -0700397 call->unmarshall++;
398
David Howells196ee9c2017-01-05 10:38:34 +0000399 begin_page:
David Howells6db3ac32017-03-16 16:27:44 +0000400 ASSERTCMP(req->index, <, req->nr_pages);
David Howells196ee9c2017-01-05 10:38:34 +0000401 if (req->remain > PAGE_SIZE - call->offset)
402 size = PAGE_SIZE - call->offset;
403 else
404 size = req->remain;
405 call->count = call->offset + size;
406 ASSERTCMP(call->count, <=, PAGE_SIZE);
407 req->remain -= size;
408
David Howells08e0e7c2007-04-26 15:55:03 -0700409 /* extract the returned data */
David Howellsb9b1f8d2007-05-10 03:15:21 -0700410 case 3:
David Howells6a0e3992017-03-16 16:27:46 +0000411 _debug("extract data %llu/%llu %zu/%u",
David Howells196ee9c2017-01-05 10:38:34 +0000412 req->remain, req->actual_len, call->offset, call->count);
413
414 buffer = kmap(req->pages[req->index]);
415 ret = afs_extract_data(call, buffer, call->count, true);
416 kunmap(req->pages[req->index]);
417 if (ret < 0)
418 return ret;
419 if (call->offset == PAGE_SIZE) {
420 if (req->page_done)
421 req->page_done(call, req);
David Howells29f06982017-03-16 16:27:46 +0000422 req->index++;
David Howells196ee9c2017-01-05 10:38:34 +0000423 if (req->remain > 0) {
David Howells196ee9c2017-01-05 10:38:34 +0000424 call->offset = 0;
David Howellse8e581a2017-03-16 16:27:44 +0000425 if (req->index >= req->nr_pages) {
426 call->unmarshall = 4;
David Howells6db3ac32017-03-16 16:27:44 +0000427 goto begin_discard;
David Howellse8e581a2017-03-16 16:27:44 +0000428 }
David Howells196ee9c2017-01-05 10:38:34 +0000429 goto begin_page;
430 }
David Howells08e0e7c2007-04-26 15:55:03 -0700431 }
David Howells6db3ac32017-03-16 16:27:44 +0000432 goto no_more_data;
433
434 /* Discard any excess data the server gave us */
435 begin_discard:
436 case 4:
David Howells6a0e3992017-03-16 16:27:46 +0000437 size = min_t(loff_t, sizeof(afs_discard_buffer), req->remain);
David Howells6db3ac32017-03-16 16:27:44 +0000438 call->count = size;
David Howells6a0e3992017-03-16 16:27:46 +0000439 _debug("extract discard %llu/%llu %zu/%u",
David Howells6db3ac32017-03-16 16:27:44 +0000440 req->remain, req->actual_len, call->offset, call->count);
441
442 call->offset = 0;
443 ret = afs_extract_data(call, afs_discard_buffer, call->count, true);
444 req->remain -= call->offset;
445 if (ret < 0)
446 return ret;
447 if (req->remain > 0)
448 goto begin_discard;
David Howells08e0e7c2007-04-26 15:55:03 -0700449
David Howells196ee9c2017-01-05 10:38:34 +0000450 no_more_data:
David Howells08e0e7c2007-04-26 15:55:03 -0700451 call->offset = 0;
David Howells6db3ac32017-03-16 16:27:44 +0000452 call->unmarshall = 5;
David Howells08e0e7c2007-04-26 15:55:03 -0700453
454 /* extract the metadata */
David Howells6db3ac32017-03-16 16:27:44 +0000455 case 5:
David Howellsd0016482016-08-30 20:42:14 +0100456 ret = afs_extract_data(call, call->buffer,
457 (21 + 3 + 6) * 4, false);
David Howells372ee162016-08-03 14:11:40 +0100458 if (ret < 0)
459 return ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700460
461 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700462 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howellsc435ee32017-11-02 15:27:49 +0000463 xdr_decode_AFSCallBack(call, vnode, &bp);
David Howells97e30432017-11-02 15:27:48 +0000464 if (call->reply[1])
465 xdr_decode_AFSVolSync(&bp, call->reply[1]);
David Howells08e0e7c2007-04-26 15:55:03 -0700466
467 call->offset = 0;
468 call->unmarshall++;
469
David Howells6db3ac32017-03-16 16:27:44 +0000470 case 6:
David Howells08e0e7c2007-04-26 15:55:03 -0700471 break;
472 }
473
David Howells6db3ac32017-03-16 16:27:44 +0000474 for (; req->index < req->nr_pages; req->index++) {
475 if (call->count < PAGE_SIZE)
476 zero_user_segment(req->pages[req->index],
477 call->count, PAGE_SIZE);
David Howells196ee9c2017-01-05 10:38:34 +0000478 if (req->page_done)
479 req->page_done(call, req);
David Howells6db3ac32017-03-16 16:27:44 +0000480 call->count = 0;
David Howells416351f2007-05-09 02:33:45 -0700481 }
482
David Howells08e0e7c2007-04-26 15:55:03 -0700483 _leave(" = 0 [done]");
484 return 0;
485}
486
David Howells196ee9c2017-01-05 10:38:34 +0000487static void afs_fetch_data_destructor(struct afs_call *call)
488{
David Howells97e30432017-11-02 15:27:48 +0000489 struct afs_read *req = call->reply[2];
David Howells196ee9c2017-01-05 10:38:34 +0000490
491 afs_put_read(req);
492 afs_flat_call_destructor(call);
493}
494
David Howells08e0e7c2007-04-26 15:55:03 -0700495/*
496 * FS.FetchData operation type
497 */
498static const struct afs_call_type afs_RXFSFetchData = {
David Howells00d3b7a2007-04-26 15:57:07 -0700499 .name = "FS.FetchData",
David Howells08e0e7c2007-04-26 15:55:03 -0700500 .deliver = afs_deliver_fs_fetch_data,
David Howells196ee9c2017-01-05 10:38:34 +0000501 .destructor = afs_fetch_data_destructor,
David Howells08e0e7c2007-04-26 15:55:03 -0700502};
503
David Howellsb9b1f8d2007-05-10 03:15:21 -0700504static const struct afs_call_type afs_RXFSFetchData64 = {
505 .name = "FS.FetchData64",
506 .deliver = afs_deliver_fs_fetch_data,
David Howells196ee9c2017-01-05 10:38:34 +0000507 .destructor = afs_fetch_data_destructor,
David Howellsb9b1f8d2007-05-10 03:15:21 -0700508};
509
510/*
511 * fetch data from a very large file
512 */
David Howellsd2ddc772017-11-02 15:27:50 +0000513static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
David Howellsb9b1f8d2007-05-10 03:15:21 -0700514{
David Howellsd2ddc772017-11-02 15:27:50 +0000515 struct afs_vnode *vnode = fc->vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700516 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000517 struct afs_net *net = afs_v2net(vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700518 __be32 *bp;
519
520 _enter("");
521
David Howellsf044c882017-11-02 15:27:45 +0000522 call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700523 if (!call)
524 return -ENOMEM;
525
David Howellsd2ddc772017-11-02 15:27:50 +0000526 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000527 call->reply[0] = vnode;
528 call->reply[1] = NULL; /* volsync */
529 call->reply[2] = req;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700530 call->operation_ID = FSFETCHDATA64;
531
532 /* marshall the parameters */
533 bp = call->request;
534 bp[0] = htonl(FSFETCHDATA64);
535 bp[1] = htonl(vnode->fid.vid);
536 bp[2] = htonl(vnode->fid.vnode);
537 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000538 bp[4] = htonl(upper_32_bits(req->pos));
539 bp[5] = htonl(lower_32_bits(req->pos));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700540 bp[6] = 0;
David Howells196ee9c2017-01-05 10:38:34 +0000541 bp[7] = htonl(lower_32_bits(req->len));
David Howellsb9b1f8d2007-05-10 03:15:21 -0700542
David Howells196ee9c2017-01-05 10:38:34 +0000543 atomic_inc(&req->usage);
David Howellsd2ddc772017-11-02 15:27:50 +0000544 call->cb_break = fc->cb_break;
545 afs_use_fs_server(call, fc->cbi);
546 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700547}
548
David Howells08e0e7c2007-04-26 15:55:03 -0700549/*
550 * fetch data from a file
551 */
David Howellsd2ddc772017-11-02 15:27:50 +0000552int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
David Howells08e0e7c2007-04-26 15:55:03 -0700553{
David Howellsd2ddc772017-11-02 15:27:50 +0000554 struct afs_vnode *vnode = fc->vnode;
David Howells08e0e7c2007-04-26 15:55:03 -0700555 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000556 struct afs_net *net = afs_v2net(vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 __be32 *bp;
558
David Howells196ee9c2017-01-05 10:38:34 +0000559 if (upper_32_bits(req->pos) ||
560 upper_32_bits(req->len) ||
561 upper_32_bits(req->pos + req->len))
David Howellsd2ddc772017-11-02 15:27:50 +0000562 return afs_fs_fetch_data64(fc, req);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700563
David Howells08e0e7c2007-04-26 15:55:03 -0700564 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
David Howellsf044c882017-11-02 15:27:45 +0000566 call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700567 if (!call)
568 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
David Howellsd2ddc772017-11-02 15:27:50 +0000570 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000571 call->reply[0] = vnode;
572 call->reply[1] = NULL; /* volsync */
573 call->reply[2] = req;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700574 call->operation_ID = FSFETCHDATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700577 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 bp[0] = htonl(FSFETCHDATA);
David Howells08e0e7c2007-04-26 15:55:03 -0700579 bp[1] = htonl(vnode->fid.vid);
580 bp[2] = htonl(vnode->fid.vnode);
581 bp[3] = htonl(vnode->fid.unique);
David Howells196ee9c2017-01-05 10:38:34 +0000582 bp[4] = htonl(lower_32_bits(req->pos));
583 bp[5] = htonl(lower_32_bits(req->len));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
David Howells196ee9c2017-01-05 10:38:34 +0000585 atomic_inc(&req->usage);
David Howellsd2ddc772017-11-02 15:27:50 +0000586 call->cb_break = fc->cb_break;
587 afs_use_fs_server(call, fc->cbi);
588 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsec268152007-04-26 15:49:28 -0700589}
David Howells260a9802007-04-26 15:59:35 -0700590
591/*
592 * deliver reply data to an FS.CreateFile or an FS.MakeDir
593 */
David Howellsd0016482016-08-30 20:42:14 +0100594static int afs_deliver_fs_create_vnode(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700595{
David Howells97e30432017-11-02 15:27:48 +0000596 struct afs_vnode *vnode = call->reply[0];
David Howells260a9802007-04-26 15:59:35 -0700597 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100598 int ret;
David Howells260a9802007-04-26 15:59:35 -0700599
David Howellsd0016482016-08-30 20:42:14 +0100600 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700601
David Howellsd0016482016-08-30 20:42:14 +0100602 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100603 if (ret < 0)
604 return ret;
David Howells260a9802007-04-26 15:59:35 -0700605
606 /* unmarshall the reply once we've received all of it */
607 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +0000608 xdr_decode_AFSFid(&bp, call->reply[1]);
609 xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL);
David Howells31143d52007-05-09 02:33:46 -0700610 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells97e30432017-11-02 15:27:48 +0000611 xdr_decode_AFSCallBack_raw(&bp, call->reply[3]);
612 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700613
614 _leave(" = 0 [done]");
615 return 0;
616}
617
618/*
619 * FS.CreateFile and FS.MakeDir operation type
620 */
621static const struct afs_call_type afs_RXFSCreateXXXX = {
622 .name = "FS.CreateXXXX",
623 .deliver = afs_deliver_fs_create_vnode,
David Howells260a9802007-04-26 15:59:35 -0700624 .destructor = afs_flat_call_destructor,
625};
626
627/*
628 * create a file or make a directory
629 */
David Howells8b2a4642017-11-02 15:27:50 +0000630int afs_fs_create(struct afs_fs_cursor *fc,
David Howells260a9802007-04-26 15:59:35 -0700631 const char *name,
632 umode_t mode,
633 struct afs_fid *newfid,
634 struct afs_file_status *newstatus,
David Howellsd2ddc772017-11-02 15:27:50 +0000635 struct afs_callback *newcb)
David Howells260a9802007-04-26 15:59:35 -0700636{
David Howellsd2ddc772017-11-02 15:27:50 +0000637 struct afs_vnode *vnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700638 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000639 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700640 size_t namesz, reqsz, padsz;
641 __be32 *bp;
642
643 _enter("");
644
645 namesz = strlen(name);
646 padsz = (4 - (namesz & 3)) & 3;
647 reqsz = (5 * 4) + namesz + padsz + (6 * 4);
648
David Howellsf044c882017-11-02 15:27:45 +0000649 call = afs_alloc_flat_call(net, &afs_RXFSCreateXXXX, reqsz,
David Howells260a9802007-04-26 15:59:35 -0700650 (3 + 21 + 21 + 3 + 6) * 4);
651 if (!call)
652 return -ENOMEM;
653
David Howellsd2ddc772017-11-02 15:27:50 +0000654 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000655 call->reply[0] = vnode;
656 call->reply[1] = newfid;
657 call->reply[2] = newstatus;
658 call->reply[3] = newcb;
David Howells260a9802007-04-26 15:59:35 -0700659
660 /* marshall the parameters */
661 bp = call->request;
662 *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
663 *bp++ = htonl(vnode->fid.vid);
664 *bp++ = htonl(vnode->fid.vnode);
665 *bp++ = htonl(vnode->fid.unique);
666 *bp++ = htonl(namesz);
667 memcpy(bp, name, namesz);
668 bp = (void *) bp + namesz;
669 if (padsz > 0) {
670 memset(bp, 0, padsz);
671 bp = (void *) bp + padsz;
672 }
Marc Dionneab94f5d2017-03-16 16:27:47 +0000673 *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
674 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howells260a9802007-04-26 15:59:35 -0700675 *bp++ = 0; /* owner */
676 *bp++ = 0; /* group */
677 *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
678 *bp++ = 0; /* segment size */
679
David Howellsd2ddc772017-11-02 15:27:50 +0000680 afs_use_fs_server(call, fc->cbi);
681 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700682}
683
684/*
685 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
686 */
David Howellsd0016482016-08-30 20:42:14 +0100687static int afs_deliver_fs_remove(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700688{
David Howells97e30432017-11-02 15:27:48 +0000689 struct afs_vnode *vnode = call->reply[0];
David Howells260a9802007-04-26 15:59:35 -0700690 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100691 int ret;
David Howells260a9802007-04-26 15:59:35 -0700692
David Howellsd0016482016-08-30 20:42:14 +0100693 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700694
David Howellsd0016482016-08-30 20:42:14 +0100695 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100696 if (ret < 0)
697 return ret;
David Howells260a9802007-04-26 15:59:35 -0700698
699 /* unmarshall the reply once we've received all of it */
700 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700701 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells97e30432017-11-02 15:27:48 +0000702 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700703
704 _leave(" = 0 [done]");
705 return 0;
706}
707
708/*
709 * FS.RemoveDir/FS.RemoveFile operation type
710 */
711static const struct afs_call_type afs_RXFSRemoveXXXX = {
712 .name = "FS.RemoveXXXX",
713 .deliver = afs_deliver_fs_remove,
David Howells260a9802007-04-26 15:59:35 -0700714 .destructor = afs_flat_call_destructor,
715};
716
717/*
718 * remove a file or directory
719 */
David Howellsd2ddc772017-11-02 15:27:50 +0000720int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir)
David Howells260a9802007-04-26 15:59:35 -0700721{
David Howellsd2ddc772017-11-02 15:27:50 +0000722 struct afs_vnode *vnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700723 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000724 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700725 size_t namesz, reqsz, padsz;
726 __be32 *bp;
727
728 _enter("");
729
730 namesz = strlen(name);
731 padsz = (4 - (namesz & 3)) & 3;
732 reqsz = (5 * 4) + namesz + padsz;
733
David Howellsf044c882017-11-02 15:27:45 +0000734 call = afs_alloc_flat_call(net, &afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -0700735 if (!call)
736 return -ENOMEM;
737
David Howellsd2ddc772017-11-02 15:27:50 +0000738 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000739 call->reply[0] = vnode;
David Howells260a9802007-04-26 15:59:35 -0700740
741 /* marshall the parameters */
742 bp = call->request;
743 *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
744 *bp++ = htonl(vnode->fid.vid);
745 *bp++ = htonl(vnode->fid.vnode);
746 *bp++ = htonl(vnode->fid.unique);
747 *bp++ = htonl(namesz);
748 memcpy(bp, name, namesz);
749 bp = (void *) bp + namesz;
750 if (padsz > 0) {
751 memset(bp, 0, padsz);
752 bp = (void *) bp + padsz;
753 }
754
David Howellsd2ddc772017-11-02 15:27:50 +0000755 afs_use_fs_server(call, fc->cbi);
756 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700757}
758
759/*
760 * deliver reply data to an FS.Link
761 */
David Howellsd0016482016-08-30 20:42:14 +0100762static int afs_deliver_fs_link(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700763{
David Howells97e30432017-11-02 15:27:48 +0000764 struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1];
David Howells260a9802007-04-26 15:59:35 -0700765 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100766 int ret;
David Howells260a9802007-04-26 15:59:35 -0700767
David Howellsd0016482016-08-30 20:42:14 +0100768 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700769
David Howellsd0016482016-08-30 20:42:14 +0100770 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100771 if (ret < 0)
772 return ret;
David Howells260a9802007-04-26 15:59:35 -0700773
774 /* unmarshall the reply once we've received all of it */
775 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700776 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
777 xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
David Howells97e30432017-11-02 15:27:48 +0000778 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700779
780 _leave(" = 0 [done]");
781 return 0;
782}
783
784/*
785 * FS.Link operation type
786 */
787static const struct afs_call_type afs_RXFSLink = {
788 .name = "FS.Link",
789 .deliver = afs_deliver_fs_link,
David Howells260a9802007-04-26 15:59:35 -0700790 .destructor = afs_flat_call_destructor,
791};
792
793/*
794 * make a hard link
795 */
David Howellsd2ddc772017-11-02 15:27:50 +0000796int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
797 const char *name)
David Howells260a9802007-04-26 15:59:35 -0700798{
David Howellsd2ddc772017-11-02 15:27:50 +0000799 struct afs_vnode *dvnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700800 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000801 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700802 size_t namesz, reqsz, padsz;
803 __be32 *bp;
804
805 _enter("");
806
807 namesz = strlen(name);
808 padsz = (4 - (namesz & 3)) & 3;
809 reqsz = (5 * 4) + namesz + padsz + (3 * 4);
810
David Howellsf044c882017-11-02 15:27:45 +0000811 call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -0700812 if (!call)
813 return -ENOMEM;
814
David Howellsd2ddc772017-11-02 15:27:50 +0000815 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000816 call->reply[0] = dvnode;
817 call->reply[1] = vnode;
David Howells260a9802007-04-26 15:59:35 -0700818
819 /* marshall the parameters */
820 bp = call->request;
821 *bp++ = htonl(FSLINK);
822 *bp++ = htonl(dvnode->fid.vid);
823 *bp++ = htonl(dvnode->fid.vnode);
824 *bp++ = htonl(dvnode->fid.unique);
825 *bp++ = htonl(namesz);
826 memcpy(bp, name, namesz);
827 bp = (void *) bp + namesz;
828 if (padsz > 0) {
829 memset(bp, 0, padsz);
830 bp = (void *) bp + padsz;
831 }
832 *bp++ = htonl(vnode->fid.vid);
833 *bp++ = htonl(vnode->fid.vnode);
834 *bp++ = htonl(vnode->fid.unique);
835
David Howellsd2ddc772017-11-02 15:27:50 +0000836 afs_use_fs_server(call, fc->cbi);
837 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700838}
839
840/*
841 * deliver reply data to an FS.Symlink
842 */
David Howellsd0016482016-08-30 20:42:14 +0100843static int afs_deliver_fs_symlink(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700844{
David Howells97e30432017-11-02 15:27:48 +0000845 struct afs_vnode *vnode = call->reply[0];
David Howells260a9802007-04-26 15:59:35 -0700846 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100847 int ret;
David Howells260a9802007-04-26 15:59:35 -0700848
David Howellsd0016482016-08-30 20:42:14 +0100849 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700850
David Howellsd0016482016-08-30 20:42:14 +0100851 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100852 if (ret < 0)
853 return ret;
David Howells260a9802007-04-26 15:59:35 -0700854
855 /* unmarshall the reply once we've received all of it */
856 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +0000857 xdr_decode_AFSFid(&bp, call->reply[1]);
858 xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL);
David Howells31143d52007-05-09 02:33:46 -0700859 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells97e30432017-11-02 15:27:48 +0000860 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700861
862 _leave(" = 0 [done]");
863 return 0;
864}
865
866/*
867 * FS.Symlink operation type
868 */
869static const struct afs_call_type afs_RXFSSymlink = {
870 .name = "FS.Symlink",
871 .deliver = afs_deliver_fs_symlink,
David Howells260a9802007-04-26 15:59:35 -0700872 .destructor = afs_flat_call_destructor,
873};
874
875/*
876 * create a symbolic link
877 */
David Howells8b2a4642017-11-02 15:27:50 +0000878int afs_fs_symlink(struct afs_fs_cursor *fc,
David Howells260a9802007-04-26 15:59:35 -0700879 const char *name,
880 const char *contents,
881 struct afs_fid *newfid,
David Howellsd2ddc772017-11-02 15:27:50 +0000882 struct afs_file_status *newstatus)
David Howells260a9802007-04-26 15:59:35 -0700883{
David Howellsd2ddc772017-11-02 15:27:50 +0000884 struct afs_vnode *vnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700885 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000886 struct afs_net *net = afs_v2net(vnode);
David Howells260a9802007-04-26 15:59:35 -0700887 size_t namesz, reqsz, padsz, c_namesz, c_padsz;
888 __be32 *bp;
889
890 _enter("");
891
892 namesz = strlen(name);
893 padsz = (4 - (namesz & 3)) & 3;
894
895 c_namesz = strlen(contents);
896 c_padsz = (4 - (c_namesz & 3)) & 3;
897
898 reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
899
David Howellsf044c882017-11-02 15:27:45 +0000900 call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
David Howells260a9802007-04-26 15:59:35 -0700901 (3 + 21 + 21 + 6) * 4);
902 if (!call)
903 return -ENOMEM;
904
David Howellsd2ddc772017-11-02 15:27:50 +0000905 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +0000906 call->reply[0] = vnode;
907 call->reply[1] = newfid;
908 call->reply[2] = newstatus;
David Howells260a9802007-04-26 15:59:35 -0700909
910 /* marshall the parameters */
911 bp = call->request;
912 *bp++ = htonl(FSSYMLINK);
913 *bp++ = htonl(vnode->fid.vid);
914 *bp++ = htonl(vnode->fid.vnode);
915 *bp++ = htonl(vnode->fid.unique);
916 *bp++ = htonl(namesz);
917 memcpy(bp, name, namesz);
918 bp = (void *) bp + namesz;
919 if (padsz > 0) {
920 memset(bp, 0, padsz);
921 bp = (void *) bp + padsz;
922 }
923 *bp++ = htonl(c_namesz);
924 memcpy(bp, contents, c_namesz);
925 bp = (void *) bp + c_namesz;
926 if (c_padsz > 0) {
927 memset(bp, 0, c_padsz);
928 bp = (void *) bp + c_padsz;
929 }
Marc Dionneab94f5d2017-03-16 16:27:47 +0000930 *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
931 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howells260a9802007-04-26 15:59:35 -0700932 *bp++ = 0; /* owner */
933 *bp++ = 0; /* group */
934 *bp++ = htonl(S_IRWXUGO); /* unix mode */
935 *bp++ = 0; /* segment size */
936
David Howellsd2ddc772017-11-02 15:27:50 +0000937 afs_use_fs_server(call, fc->cbi);
938 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -0700939}
940
941/*
942 * deliver reply data to an FS.Rename
943 */
David Howellsd0016482016-08-30 20:42:14 +0100944static int afs_deliver_fs_rename(struct afs_call *call)
David Howells260a9802007-04-26 15:59:35 -0700945{
David Howells97e30432017-11-02 15:27:48 +0000946 struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1];
David Howells260a9802007-04-26 15:59:35 -0700947 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +0100948 int ret;
David Howells260a9802007-04-26 15:59:35 -0700949
David Howellsd0016482016-08-30 20:42:14 +0100950 _enter("{%u}", call->unmarshall);
David Howells260a9802007-04-26 15:59:35 -0700951
David Howellsd0016482016-08-30 20:42:14 +0100952 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +0100953 if (ret < 0)
954 return ret;
David Howells260a9802007-04-26 15:59:35 -0700955
956 /* unmarshall the reply once we've received all of it */
957 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700958 xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700959 if (new_dvnode != orig_dvnode)
David Howells31143d52007-05-09 02:33:46 -0700960 xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
961 NULL);
David Howells97e30432017-11-02 15:27:48 +0000962 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells260a9802007-04-26 15:59:35 -0700963
964 _leave(" = 0 [done]");
965 return 0;
966}
967
968/*
969 * FS.Rename operation type
970 */
971static const struct afs_call_type afs_RXFSRename = {
972 .name = "FS.Rename",
973 .deliver = afs_deliver_fs_rename,
David Howells260a9802007-04-26 15:59:35 -0700974 .destructor = afs_flat_call_destructor,
975};
976
977/*
978 * create a symbolic link
979 */
David Howells8b2a4642017-11-02 15:27:50 +0000980int afs_fs_rename(struct afs_fs_cursor *fc,
David Howells260a9802007-04-26 15:59:35 -0700981 const char *orig_name,
982 struct afs_vnode *new_dvnode,
David Howellsd2ddc772017-11-02 15:27:50 +0000983 const char *new_name)
David Howells260a9802007-04-26 15:59:35 -0700984{
David Howellsd2ddc772017-11-02 15:27:50 +0000985 struct afs_vnode *orig_dvnode = fc->vnode;
David Howells260a9802007-04-26 15:59:35 -0700986 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +0000987 struct afs_net *net = afs_v2net(orig_dvnode);
David Howells260a9802007-04-26 15:59:35 -0700988 size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
989 __be32 *bp;
990
991 _enter("");
992
993 o_namesz = strlen(orig_name);
994 o_padsz = (4 - (o_namesz & 3)) & 3;
995
996 n_namesz = strlen(new_name);
997 n_padsz = (4 - (n_namesz & 3)) & 3;
998
999 reqsz = (4 * 4) +
1000 4 + o_namesz + o_padsz +
1001 (3 * 4) +
1002 4 + n_namesz + n_padsz;
1003
David Howellsf044c882017-11-02 15:27:45 +00001004 call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
David Howells260a9802007-04-26 15:59:35 -07001005 if (!call)
1006 return -ENOMEM;
1007
David Howellsd2ddc772017-11-02 15:27:50 +00001008 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001009 call->reply[0] = orig_dvnode;
1010 call->reply[1] = new_dvnode;
David Howells260a9802007-04-26 15:59:35 -07001011
1012 /* marshall the parameters */
1013 bp = call->request;
1014 *bp++ = htonl(FSRENAME);
1015 *bp++ = htonl(orig_dvnode->fid.vid);
1016 *bp++ = htonl(orig_dvnode->fid.vnode);
1017 *bp++ = htonl(orig_dvnode->fid.unique);
1018 *bp++ = htonl(o_namesz);
1019 memcpy(bp, orig_name, o_namesz);
1020 bp = (void *) bp + o_namesz;
1021 if (o_padsz > 0) {
1022 memset(bp, 0, o_padsz);
1023 bp = (void *) bp + o_padsz;
1024 }
1025
1026 *bp++ = htonl(new_dvnode->fid.vid);
1027 *bp++ = htonl(new_dvnode->fid.vnode);
1028 *bp++ = htonl(new_dvnode->fid.unique);
1029 *bp++ = htonl(n_namesz);
1030 memcpy(bp, new_name, n_namesz);
1031 bp = (void *) bp + n_namesz;
1032 if (n_padsz > 0) {
1033 memset(bp, 0, n_padsz);
1034 bp = (void *) bp + n_padsz;
1035 }
1036
David Howellsd2ddc772017-11-02 15:27:50 +00001037 afs_use_fs_server(call, fc->cbi);
1038 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells260a9802007-04-26 15:59:35 -07001039}
David Howells31143d52007-05-09 02:33:46 -07001040
1041/*
1042 * deliver reply data to an FS.StoreData
1043 */
David Howellsd0016482016-08-30 20:42:14 +01001044static int afs_deliver_fs_store_data(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001045{
David Howells97e30432017-11-02 15:27:48 +00001046 struct afs_vnode *vnode = call->reply[0];
David Howells31143d52007-05-09 02:33:46 -07001047 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001048 int ret;
David Howells31143d52007-05-09 02:33:46 -07001049
David Howellsd0016482016-08-30 20:42:14 +01001050 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001051
David Howellsd0016482016-08-30 20:42:14 +01001052 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001053 if (ret < 0)
1054 return ret;
David Howells31143d52007-05-09 02:33:46 -07001055
1056 /* unmarshall the reply once we've received all of it */
1057 bp = call->buffer;
1058 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
1059 &call->store_version);
David Howells97e30432017-11-02 15:27:48 +00001060 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells31143d52007-05-09 02:33:46 -07001061
1062 afs_pages_written_back(vnode, call);
1063
1064 _leave(" = 0 [done]");
1065 return 0;
1066}
1067
1068/*
1069 * FS.StoreData operation type
1070 */
1071static const struct afs_call_type afs_RXFSStoreData = {
1072 .name = "FS.StoreData",
1073 .deliver = afs_deliver_fs_store_data,
David Howells31143d52007-05-09 02:33:46 -07001074 .destructor = afs_flat_call_destructor,
1075};
1076
David Howellsb9b1f8d2007-05-10 03:15:21 -07001077static const struct afs_call_type afs_RXFSStoreData64 = {
1078 .name = "FS.StoreData64",
1079 .deliver = afs_deliver_fs_store_data,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001080 .destructor = afs_flat_call_destructor,
1081};
1082
1083/*
1084 * store a set of pages to a very large file
1085 */
David Howells8b2a4642017-11-02 15:27:50 +00001086static int afs_fs_store_data64(struct afs_fs_cursor *fc,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001087 struct afs_writeback *wb,
1088 pgoff_t first, pgoff_t last,
1089 unsigned offset, unsigned to,
David Howellsd2ddc772017-11-02 15:27:50 +00001090 loff_t size, loff_t pos, loff_t i_size)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001091{
1092 struct afs_vnode *vnode = wb->vnode;
1093 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001094 struct afs_net *net = afs_v2net(vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001095 __be32 *bp;
1096
1097 _enter(",%x,{%x:%u},,",
1098 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1099
David Howellsf044c882017-11-02 15:27:45 +00001100 call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001101 (4 + 6 + 3 * 2) * 4,
1102 (21 + 6) * 4);
1103 if (!call)
1104 return -ENOMEM;
1105
1106 call->wb = wb;
1107 call->key = wb->key;
David Howells97e30432017-11-02 15:27:48 +00001108 call->reply[0] = vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001109 call->mapping = vnode->vfs_inode.i_mapping;
1110 call->first = first;
1111 call->last = last;
1112 call->first_offset = offset;
1113 call->last_to = to;
1114 call->send_pages = true;
1115 call->store_version = vnode->status.data_version + 1;
1116
1117 /* marshall the parameters */
1118 bp = call->request;
1119 *bp++ = htonl(FSSTOREDATA64);
1120 *bp++ = htonl(vnode->fid.vid);
1121 *bp++ = htonl(vnode->fid.vnode);
1122 *bp++ = htonl(vnode->fid.unique);
1123
Marc Dionneab94f5d2017-03-16 16:27:47 +00001124 *bp++ = htonl(AFS_SET_MTIME); /* mask */
1125 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howellsb9b1f8d2007-05-10 03:15:21 -07001126 *bp++ = 0; /* owner */
1127 *bp++ = 0; /* group */
1128 *bp++ = 0; /* unix mode */
1129 *bp++ = 0; /* segment size */
1130
1131 *bp++ = htonl(pos >> 32);
1132 *bp++ = htonl((u32) pos);
1133 *bp++ = htonl(size >> 32);
1134 *bp++ = htonl((u32) size);
1135 *bp++ = htonl(i_size >> 32);
1136 *bp++ = htonl((u32) i_size);
1137
David Howellsd2ddc772017-11-02 15:27:50 +00001138 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001139}
1140
David Howells31143d52007-05-09 02:33:46 -07001141/*
1142 * store a set of pages
1143 */
David Howells8b2a4642017-11-02 15:27:50 +00001144int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb,
David Howells31143d52007-05-09 02:33:46 -07001145 pgoff_t first, pgoff_t last,
David Howellsd2ddc772017-11-02 15:27:50 +00001146 unsigned offset, unsigned to)
David Howells31143d52007-05-09 02:33:46 -07001147{
1148 struct afs_vnode *vnode = wb->vnode;
1149 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001150 struct afs_net *net = afs_v2net(vnode);
David Howells31143d52007-05-09 02:33:46 -07001151 loff_t size, pos, i_size;
1152 __be32 *bp;
1153
1154 _enter(",%x,{%x:%u},,",
1155 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1156
David Howells146a1192017-03-16 16:27:47 +00001157 size = (loff_t)to - (loff_t)offset;
David Howells31143d52007-05-09 02:33:46 -07001158 if (first != last)
1159 size += (loff_t)(last - first) << PAGE_SHIFT;
1160 pos = (loff_t)first << PAGE_SHIFT;
1161 pos += offset;
1162
1163 i_size = i_size_read(&vnode->vfs_inode);
1164 if (pos + size > i_size)
1165 i_size = size + pos;
1166
1167 _debug("size %llx, at %llx, i_size %llx",
1168 (unsigned long long) size, (unsigned long long) pos,
1169 (unsigned long long) i_size);
1170
David Howellsb9b1f8d2007-05-10 03:15:21 -07001171 if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
David Howells8b2a4642017-11-02 15:27:50 +00001172 return afs_fs_store_data64(fc, wb, first, last, offset, to,
David Howellsd2ddc772017-11-02 15:27:50 +00001173 size, pos, i_size);
David Howells31143d52007-05-09 02:33:46 -07001174
David Howellsf044c882017-11-02 15:27:45 +00001175 call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
David Howells31143d52007-05-09 02:33:46 -07001176 (4 + 6 + 3) * 4,
1177 (21 + 6) * 4);
1178 if (!call)
1179 return -ENOMEM;
1180
1181 call->wb = wb;
1182 call->key = wb->key;
David Howells97e30432017-11-02 15:27:48 +00001183 call->reply[0] = vnode;
David Howells31143d52007-05-09 02:33:46 -07001184 call->mapping = vnode->vfs_inode.i_mapping;
1185 call->first = first;
1186 call->last = last;
1187 call->first_offset = offset;
1188 call->last_to = to;
1189 call->send_pages = true;
1190 call->store_version = vnode->status.data_version + 1;
1191
1192 /* marshall the parameters */
1193 bp = call->request;
1194 *bp++ = htonl(FSSTOREDATA);
1195 *bp++ = htonl(vnode->fid.vid);
1196 *bp++ = htonl(vnode->fid.vnode);
1197 *bp++ = htonl(vnode->fid.unique);
1198
Marc Dionneab94f5d2017-03-16 16:27:47 +00001199 *bp++ = htonl(AFS_SET_MTIME); /* mask */
1200 *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
David Howells31143d52007-05-09 02:33:46 -07001201 *bp++ = 0; /* owner */
1202 *bp++ = 0; /* group */
1203 *bp++ = 0; /* unix mode */
1204 *bp++ = 0; /* segment size */
1205
1206 *bp++ = htonl(pos);
1207 *bp++ = htonl(size);
1208 *bp++ = htonl(i_size);
1209
David Howellsd2ddc772017-11-02 15:27:50 +00001210 afs_use_fs_server(call, fc->cbi);
1211 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells31143d52007-05-09 02:33:46 -07001212}
1213
1214/*
1215 * deliver reply data to an FS.StoreStatus
1216 */
David Howellsd0016482016-08-30 20:42:14 +01001217static int afs_deliver_fs_store_status(struct afs_call *call)
David Howells31143d52007-05-09 02:33:46 -07001218{
1219 afs_dataversion_t *store_version;
David Howells97e30432017-11-02 15:27:48 +00001220 struct afs_vnode *vnode = call->reply[0];
David Howells31143d52007-05-09 02:33:46 -07001221 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001222 int ret;
David Howells31143d52007-05-09 02:33:46 -07001223
David Howellsd0016482016-08-30 20:42:14 +01001224 _enter("");
David Howells31143d52007-05-09 02:33:46 -07001225
David Howellsd0016482016-08-30 20:42:14 +01001226 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001227 if (ret < 0)
1228 return ret;
David Howells31143d52007-05-09 02:33:46 -07001229
1230 /* unmarshall the reply once we've received all of it */
1231 store_version = NULL;
1232 if (call->operation_ID == FSSTOREDATA)
1233 store_version = &call->store_version;
1234
1235 bp = call->buffer;
1236 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
David Howells97e30432017-11-02 15:27:48 +00001237 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howells31143d52007-05-09 02:33:46 -07001238
1239 _leave(" = 0 [done]");
1240 return 0;
1241}
1242
1243/*
1244 * FS.StoreStatus operation type
1245 */
1246static const struct afs_call_type afs_RXFSStoreStatus = {
1247 .name = "FS.StoreStatus",
1248 .deliver = afs_deliver_fs_store_status,
David Howells31143d52007-05-09 02:33:46 -07001249 .destructor = afs_flat_call_destructor,
1250};
1251
1252static const struct afs_call_type afs_RXFSStoreData_as_Status = {
1253 .name = "FS.StoreData",
1254 .deliver = afs_deliver_fs_store_status,
David Howells31143d52007-05-09 02:33:46 -07001255 .destructor = afs_flat_call_destructor,
1256};
1257
David Howellsb9b1f8d2007-05-10 03:15:21 -07001258static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1259 .name = "FS.StoreData64",
1260 .deliver = afs_deliver_fs_store_status,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001261 .destructor = afs_flat_call_destructor,
1262};
1263
1264/*
1265 * set the attributes on a very large file, using FS.StoreData rather than
1266 * FS.StoreStatus so as to alter the file size also
1267 */
David Howellsd2ddc772017-11-02 15:27:50 +00001268static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
David Howellsb9b1f8d2007-05-10 03:15:21 -07001269{
David Howellsd2ddc772017-11-02 15:27:50 +00001270 struct afs_vnode *vnode = fc->vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001271 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001272 struct afs_net *net = afs_v2net(vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001273 __be32 *bp;
1274
1275 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +00001276 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001277
1278 ASSERT(attr->ia_valid & ATTR_SIZE);
1279
David Howellsf044c882017-11-02 15:27:45 +00001280 call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
David Howellsb9b1f8d2007-05-10 03:15:21 -07001281 (4 + 6 + 3 * 2) * 4,
1282 (21 + 6) * 4);
1283 if (!call)
1284 return -ENOMEM;
1285
David Howellsd2ddc772017-11-02 15:27:50 +00001286 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001287 call->reply[0] = vnode;
David Howellsb9b1f8d2007-05-10 03:15:21 -07001288 call->store_version = vnode->status.data_version + 1;
1289 call->operation_ID = FSSTOREDATA;
1290
1291 /* marshall the parameters */
1292 bp = call->request;
1293 *bp++ = htonl(FSSTOREDATA64);
1294 *bp++ = htonl(vnode->fid.vid);
1295 *bp++ = htonl(vnode->fid.vnode);
1296 *bp++ = htonl(vnode->fid.unique);
1297
1298 xdr_encode_AFS_StoreStatus(&bp, attr);
1299
1300 *bp++ = 0; /* position of start of write */
1301 *bp++ = 0;
1302 *bp++ = 0; /* size of write */
1303 *bp++ = 0;
1304 *bp++ = htonl(attr->ia_size >> 32); /* new file length */
1305 *bp++ = htonl((u32) attr->ia_size);
1306
David Howellsd2ddc772017-11-02 15:27:50 +00001307 afs_use_fs_server(call, fc->cbi);
1308 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001309}
1310
David Howells31143d52007-05-09 02:33:46 -07001311/*
1312 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
1313 * so as to alter the file size also
1314 */
David Howellsd2ddc772017-11-02 15:27:50 +00001315static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
David Howells31143d52007-05-09 02:33:46 -07001316{
David Howellsd2ddc772017-11-02 15:27:50 +00001317 struct afs_vnode *vnode = fc->vnode;
David Howells31143d52007-05-09 02:33:46 -07001318 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001319 struct afs_net *net = afs_v2net(vnode);
David Howells31143d52007-05-09 02:33:46 -07001320 __be32 *bp;
1321
1322 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +00001323 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howells31143d52007-05-09 02:33:46 -07001324
1325 ASSERT(attr->ia_valid & ATTR_SIZE);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001326 if (attr->ia_size >> 32)
David Howellsd2ddc772017-11-02 15:27:50 +00001327 return afs_fs_setattr_size64(fc, attr);
David Howells31143d52007-05-09 02:33:46 -07001328
David Howellsf044c882017-11-02 15:27:45 +00001329 call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
David Howells31143d52007-05-09 02:33:46 -07001330 (4 + 6 + 3) * 4,
1331 (21 + 6) * 4);
1332 if (!call)
1333 return -ENOMEM;
1334
David Howellsd2ddc772017-11-02 15:27:50 +00001335 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001336 call->reply[0] = vnode;
David Howells31143d52007-05-09 02:33:46 -07001337 call->store_version = vnode->status.data_version + 1;
1338 call->operation_ID = FSSTOREDATA;
1339
1340 /* marshall the parameters */
1341 bp = call->request;
1342 *bp++ = htonl(FSSTOREDATA);
1343 *bp++ = htonl(vnode->fid.vid);
1344 *bp++ = htonl(vnode->fid.vnode);
1345 *bp++ = htonl(vnode->fid.unique);
1346
1347 xdr_encode_AFS_StoreStatus(&bp, attr);
1348
1349 *bp++ = 0; /* position of start of write */
1350 *bp++ = 0; /* size of write */
1351 *bp++ = htonl(attr->ia_size); /* new file length */
1352
David Howellsd2ddc772017-11-02 15:27:50 +00001353 afs_use_fs_server(call, fc->cbi);
1354 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells31143d52007-05-09 02:33:46 -07001355}
1356
1357/*
1358 * set the attributes on a file, using FS.StoreData if there's a change in file
1359 * size, and FS.StoreStatus otherwise
1360 */
David Howellsd2ddc772017-11-02 15:27:50 +00001361int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
David Howells31143d52007-05-09 02:33:46 -07001362{
David Howellsd2ddc772017-11-02 15:27:50 +00001363 struct afs_vnode *vnode = fc->vnode;
David Howells31143d52007-05-09 02:33:46 -07001364 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001365 struct afs_net *net = afs_v2net(vnode);
David Howells31143d52007-05-09 02:33:46 -07001366 __be32 *bp;
1367
1368 if (attr->ia_valid & ATTR_SIZE)
David Howellsd2ddc772017-11-02 15:27:50 +00001369 return afs_fs_setattr_size(fc, attr);
David Howells31143d52007-05-09 02:33:46 -07001370
1371 _enter(",%x,{%x:%u},,",
David Howellsd2ddc772017-11-02 15:27:50 +00001372 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
David Howells31143d52007-05-09 02:33:46 -07001373
David Howellsf044c882017-11-02 15:27:45 +00001374 call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
David Howells31143d52007-05-09 02:33:46 -07001375 (4 + 6) * 4,
1376 (21 + 6) * 4);
1377 if (!call)
1378 return -ENOMEM;
1379
David Howellsd2ddc772017-11-02 15:27:50 +00001380 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001381 call->reply[0] = vnode;
David Howells31143d52007-05-09 02:33:46 -07001382 call->operation_ID = FSSTORESTATUS;
1383
1384 /* marshall the parameters */
1385 bp = call->request;
1386 *bp++ = htonl(FSSTORESTATUS);
1387 *bp++ = htonl(vnode->fid.vid);
1388 *bp++ = htonl(vnode->fid.vnode);
1389 *bp++ = htonl(vnode->fid.unique);
1390
1391 xdr_encode_AFS_StoreStatus(&bp, attr);
1392
David Howellsd2ddc772017-11-02 15:27:50 +00001393 afs_use_fs_server(call, fc->cbi);
1394 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells31143d52007-05-09 02:33:46 -07001395}
David Howells45222b92007-05-10 22:22:20 -07001396
1397/*
1398 * deliver reply data to an FS.GetVolumeStatus
1399 */
David Howellsd0016482016-08-30 20:42:14 +01001400static int afs_deliver_fs_get_volume_status(struct afs_call *call)
David Howells45222b92007-05-10 22:22:20 -07001401{
1402 const __be32 *bp;
1403 char *p;
1404 int ret;
1405
David Howellsd0016482016-08-30 20:42:14 +01001406 _enter("{%u}", call->unmarshall);
David Howells45222b92007-05-10 22:22:20 -07001407
1408 switch (call->unmarshall) {
1409 case 0:
1410 call->offset = 0;
1411 call->unmarshall++;
1412
1413 /* extract the returned status record */
1414 case 1:
1415 _debug("extract status");
David Howellsd0016482016-08-30 20:42:14 +01001416 ret = afs_extract_data(call, call->buffer,
1417 12 * 4, true);
David Howells372ee162016-08-03 14:11:40 +01001418 if (ret < 0)
1419 return ret;
David Howells45222b92007-05-10 22:22:20 -07001420
1421 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +00001422 xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]);
David Howells45222b92007-05-10 22:22:20 -07001423 call->offset = 0;
1424 call->unmarshall++;
1425
1426 /* extract the volume name length */
1427 case 2:
David Howellsd0016482016-08-30 20:42:14 +01001428 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001429 if (ret < 0)
1430 return ret;
David Howells45222b92007-05-10 22:22:20 -07001431
1432 call->count = ntohl(call->tmp);
1433 _debug("volname length: %u", call->count);
1434 if (call->count >= AFSNAMEMAX)
1435 return -EBADMSG;
1436 call->offset = 0;
1437 call->unmarshall++;
1438
1439 /* extract the volume name */
1440 case 3:
1441 _debug("extract volname");
1442 if (call->count > 0) {
David Howells97e30432017-11-02 15:27:48 +00001443 ret = afs_extract_data(call, call->reply[2],
David Howellsd0016482016-08-30 20:42:14 +01001444 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001445 if (ret < 0)
1446 return ret;
David Howells45222b92007-05-10 22:22:20 -07001447 }
1448
David Howells97e30432017-11-02 15:27:48 +00001449 p = call->reply[2];
David Howells45222b92007-05-10 22:22:20 -07001450 p[call->count] = 0;
1451 _debug("volname '%s'", p);
1452
1453 call->offset = 0;
1454 call->unmarshall++;
1455
1456 /* extract the volume name padding */
1457 if ((call->count & 3) == 0) {
1458 call->unmarshall++;
1459 goto no_volname_padding;
1460 }
1461 call->count = 4 - (call->count & 3);
1462
1463 case 4:
David Howellsd0016482016-08-30 20:42:14 +01001464 ret = afs_extract_data(call, call->buffer,
1465 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001466 if (ret < 0)
1467 return ret;
David Howells45222b92007-05-10 22:22:20 -07001468
1469 call->offset = 0;
1470 call->unmarshall++;
1471 no_volname_padding:
1472
1473 /* extract the offline message length */
1474 case 5:
David Howellsd0016482016-08-30 20:42:14 +01001475 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001476 if (ret < 0)
1477 return ret;
David Howells45222b92007-05-10 22:22:20 -07001478
1479 call->count = ntohl(call->tmp);
1480 _debug("offline msg length: %u", call->count);
1481 if (call->count >= AFSNAMEMAX)
1482 return -EBADMSG;
1483 call->offset = 0;
1484 call->unmarshall++;
1485
1486 /* extract the offline message */
1487 case 6:
1488 _debug("extract offline");
1489 if (call->count > 0) {
David Howells97e30432017-11-02 15:27:48 +00001490 ret = afs_extract_data(call, call->reply[2],
David Howellsd0016482016-08-30 20:42:14 +01001491 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001492 if (ret < 0)
1493 return ret;
David Howells45222b92007-05-10 22:22:20 -07001494 }
1495
David Howells97e30432017-11-02 15:27:48 +00001496 p = call->reply[2];
David Howells45222b92007-05-10 22:22:20 -07001497 p[call->count] = 0;
1498 _debug("offline '%s'", p);
1499
1500 call->offset = 0;
1501 call->unmarshall++;
1502
1503 /* extract the offline message padding */
1504 if ((call->count & 3) == 0) {
1505 call->unmarshall++;
1506 goto no_offline_padding;
1507 }
1508 call->count = 4 - (call->count & 3);
1509
1510 case 7:
David Howellsd0016482016-08-30 20:42:14 +01001511 ret = afs_extract_data(call, call->buffer,
1512 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001513 if (ret < 0)
1514 return ret;
David Howells45222b92007-05-10 22:22:20 -07001515
1516 call->offset = 0;
1517 call->unmarshall++;
1518 no_offline_padding:
1519
1520 /* extract the message of the day length */
1521 case 8:
David Howellsd0016482016-08-30 20:42:14 +01001522 ret = afs_extract_data(call, &call->tmp, 4, true);
David Howells372ee162016-08-03 14:11:40 +01001523 if (ret < 0)
1524 return ret;
David Howells45222b92007-05-10 22:22:20 -07001525
1526 call->count = ntohl(call->tmp);
1527 _debug("motd length: %u", call->count);
1528 if (call->count >= AFSNAMEMAX)
1529 return -EBADMSG;
1530 call->offset = 0;
1531 call->unmarshall++;
1532
1533 /* extract the message of the day */
1534 case 9:
1535 _debug("extract motd");
1536 if (call->count > 0) {
David Howells97e30432017-11-02 15:27:48 +00001537 ret = afs_extract_data(call, call->reply[2],
David Howellsd0016482016-08-30 20:42:14 +01001538 call->count, true);
David Howells372ee162016-08-03 14:11:40 +01001539 if (ret < 0)
1540 return ret;
David Howells45222b92007-05-10 22:22:20 -07001541 }
1542
David Howells97e30432017-11-02 15:27:48 +00001543 p = call->reply[2];
David Howells45222b92007-05-10 22:22:20 -07001544 p[call->count] = 0;
1545 _debug("motd '%s'", p);
1546
1547 call->offset = 0;
1548 call->unmarshall++;
1549
1550 /* extract the message of the day padding */
David Howellsd0016482016-08-30 20:42:14 +01001551 call->count = (4 - (call->count & 3)) & 3;
David Howells45222b92007-05-10 22:22:20 -07001552
1553 case 10:
David Howellsd0016482016-08-30 20:42:14 +01001554 ret = afs_extract_data(call, call->buffer,
1555 call->count, false);
David Howells372ee162016-08-03 14:11:40 +01001556 if (ret < 0)
1557 return ret;
David Howells45222b92007-05-10 22:22:20 -07001558
1559 call->offset = 0;
1560 call->unmarshall++;
David Howells45222b92007-05-10 22:22:20 -07001561 case 11:
David Howells45222b92007-05-10 22:22:20 -07001562 break;
1563 }
1564
David Howells45222b92007-05-10 22:22:20 -07001565 _leave(" = 0 [done]");
1566 return 0;
1567}
1568
1569/*
1570 * destroy an FS.GetVolumeStatus call
1571 */
1572static void afs_get_volume_status_call_destructor(struct afs_call *call)
1573{
David Howells97e30432017-11-02 15:27:48 +00001574 kfree(call->reply[2]);
1575 call->reply[2] = NULL;
David Howells45222b92007-05-10 22:22:20 -07001576 afs_flat_call_destructor(call);
1577}
1578
1579/*
1580 * FS.GetVolumeStatus operation type
1581 */
1582static const struct afs_call_type afs_RXFSGetVolumeStatus = {
1583 .name = "FS.GetVolumeStatus",
1584 .deliver = afs_deliver_fs_get_volume_status,
David Howells45222b92007-05-10 22:22:20 -07001585 .destructor = afs_get_volume_status_call_destructor,
1586};
1587
1588/*
1589 * fetch the status of a volume
1590 */
David Howells8b2a4642017-11-02 15:27:50 +00001591int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
David Howellsd2ddc772017-11-02 15:27:50 +00001592 struct afs_volume_status *vs)
David Howells45222b92007-05-10 22:22:20 -07001593{
David Howellsd2ddc772017-11-02 15:27:50 +00001594 struct afs_vnode *vnode = fc->vnode;
David Howells45222b92007-05-10 22:22:20 -07001595 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001596 struct afs_net *net = afs_v2net(vnode);
David Howells45222b92007-05-10 22:22:20 -07001597 __be32 *bp;
1598 void *tmpbuf;
1599
1600 _enter("");
1601
1602 tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
1603 if (!tmpbuf)
1604 return -ENOMEM;
1605
David Howellsf044c882017-11-02 15:27:45 +00001606 call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
David Howells45222b92007-05-10 22:22:20 -07001607 if (!call) {
1608 kfree(tmpbuf);
1609 return -ENOMEM;
1610 }
1611
David Howellsd2ddc772017-11-02 15:27:50 +00001612 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001613 call->reply[0] = vnode;
1614 call->reply[1] = vs;
1615 call->reply[2] = tmpbuf;
David Howells45222b92007-05-10 22:22:20 -07001616
1617 /* marshall the parameters */
1618 bp = call->request;
1619 bp[0] = htonl(FSGETVOLUMESTATUS);
1620 bp[1] = htonl(vnode->fid.vid);
1621
David Howellsd2ddc772017-11-02 15:27:50 +00001622 afs_use_fs_server(call, fc->cbi);
1623 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howells45222b92007-05-10 22:22:20 -07001624}
David Howellse8d6c552007-07-15 23:40:12 -07001625
1626/*
1627 * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1628 */
David Howellsd0016482016-08-30 20:42:14 +01001629static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
David Howellse8d6c552007-07-15 23:40:12 -07001630{
1631 const __be32 *bp;
David Howells372ee162016-08-03 14:11:40 +01001632 int ret;
David Howellse8d6c552007-07-15 23:40:12 -07001633
David Howellsd0016482016-08-30 20:42:14 +01001634 _enter("{%u}", call->unmarshall);
David Howellse8d6c552007-07-15 23:40:12 -07001635
David Howellsd0016482016-08-30 20:42:14 +01001636 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +01001637 if (ret < 0)
1638 return ret;
David Howellse8d6c552007-07-15 23:40:12 -07001639
1640 /* unmarshall the reply once we've received all of it */
1641 bp = call->buffer;
David Howells97e30432017-11-02 15:27:48 +00001642 /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
David Howellse8d6c552007-07-15 23:40:12 -07001643
1644 _leave(" = 0 [done]");
1645 return 0;
1646}
1647
1648/*
1649 * FS.SetLock operation type
1650 */
1651static const struct afs_call_type afs_RXFSSetLock = {
1652 .name = "FS.SetLock",
1653 .deliver = afs_deliver_fs_xxxx_lock,
David Howellse8d6c552007-07-15 23:40:12 -07001654 .destructor = afs_flat_call_destructor,
1655};
1656
1657/*
1658 * FS.ExtendLock operation type
1659 */
1660static const struct afs_call_type afs_RXFSExtendLock = {
1661 .name = "FS.ExtendLock",
1662 .deliver = afs_deliver_fs_xxxx_lock,
David Howellse8d6c552007-07-15 23:40:12 -07001663 .destructor = afs_flat_call_destructor,
1664};
1665
1666/*
1667 * FS.ReleaseLock operation type
1668 */
1669static const struct afs_call_type afs_RXFSReleaseLock = {
1670 .name = "FS.ReleaseLock",
1671 .deliver = afs_deliver_fs_xxxx_lock,
David Howellse8d6c552007-07-15 23:40:12 -07001672 .destructor = afs_flat_call_destructor,
1673};
1674
1675/*
David Howellsd2ddc772017-11-02 15:27:50 +00001676 * Set a lock on a file
David Howellse8d6c552007-07-15 23:40:12 -07001677 */
David Howellsd2ddc772017-11-02 15:27:50 +00001678int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
David Howellse8d6c552007-07-15 23:40:12 -07001679{
David Howellsd2ddc772017-11-02 15:27:50 +00001680 struct afs_vnode *vnode = fc->vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001681 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001682 struct afs_net *net = afs_v2net(vnode);
David Howellse8d6c552007-07-15 23:40:12 -07001683 __be32 *bp;
1684
1685 _enter("");
1686
David Howellsf044c882017-11-02 15:27:45 +00001687 call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
David Howellse8d6c552007-07-15 23:40:12 -07001688 if (!call)
1689 return -ENOMEM;
1690
David Howellsd2ddc772017-11-02 15:27:50 +00001691 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001692 call->reply[0] = vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001693
1694 /* marshall the parameters */
1695 bp = call->request;
1696 *bp++ = htonl(FSSETLOCK);
1697 *bp++ = htonl(vnode->fid.vid);
1698 *bp++ = htonl(vnode->fid.vnode);
1699 *bp++ = htonl(vnode->fid.unique);
1700 *bp++ = htonl(type);
1701
David Howellsd2ddc772017-11-02 15:27:50 +00001702 afs_use_fs_server(call, fc->cbi);
1703 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellse8d6c552007-07-15 23:40:12 -07001704}
1705
1706/*
1707 * extend a lock on a file
1708 */
David Howellsd2ddc772017-11-02 15:27:50 +00001709int afs_fs_extend_lock(struct afs_fs_cursor *fc)
David Howellse8d6c552007-07-15 23:40:12 -07001710{
David Howellsd2ddc772017-11-02 15:27:50 +00001711 struct afs_vnode *vnode = fc->vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001712 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001713 struct afs_net *net = afs_v2net(vnode);
David Howellse8d6c552007-07-15 23:40:12 -07001714 __be32 *bp;
1715
1716 _enter("");
1717
David Howellsf044c882017-11-02 15:27:45 +00001718 call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
David Howellse8d6c552007-07-15 23:40:12 -07001719 if (!call)
1720 return -ENOMEM;
1721
David Howellsd2ddc772017-11-02 15:27:50 +00001722 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001723 call->reply[0] = vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001724
1725 /* marshall the parameters */
1726 bp = call->request;
1727 *bp++ = htonl(FSEXTENDLOCK);
1728 *bp++ = htonl(vnode->fid.vid);
1729 *bp++ = htonl(vnode->fid.vnode);
1730 *bp++ = htonl(vnode->fid.unique);
1731
David Howellsd2ddc772017-11-02 15:27:50 +00001732 afs_use_fs_server(call, fc->cbi);
1733 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellse8d6c552007-07-15 23:40:12 -07001734}
1735
1736/*
1737 * release a lock on a file
1738 */
David Howellsd2ddc772017-11-02 15:27:50 +00001739int afs_fs_release_lock(struct afs_fs_cursor *fc)
David Howellse8d6c552007-07-15 23:40:12 -07001740{
David Howellsd2ddc772017-11-02 15:27:50 +00001741 struct afs_vnode *vnode = fc->vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001742 struct afs_call *call;
David Howellsf044c882017-11-02 15:27:45 +00001743 struct afs_net *net = afs_v2net(vnode);
David Howellse8d6c552007-07-15 23:40:12 -07001744 __be32 *bp;
1745
1746 _enter("");
1747
David Howellsf044c882017-11-02 15:27:45 +00001748 call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
David Howellse8d6c552007-07-15 23:40:12 -07001749 if (!call)
1750 return -ENOMEM;
1751
David Howellsd2ddc772017-11-02 15:27:50 +00001752 call->key = fc->key;
David Howells97e30432017-11-02 15:27:48 +00001753 call->reply[0] = vnode;
David Howellse8d6c552007-07-15 23:40:12 -07001754
1755 /* marshall the parameters */
1756 bp = call->request;
1757 *bp++ = htonl(FSRELEASELOCK);
1758 *bp++ = htonl(vnode->fid.vid);
1759 *bp++ = htonl(vnode->fid.vnode);
1760 *bp++ = htonl(vnode->fid.unique);
1761
David Howellsd2ddc772017-11-02 15:27:50 +00001762 afs_use_fs_server(call, fc->cbi);
1763 return afs_make_call(&fc->ac, call, GFP_NOFS, false);
David Howellsc435ee32017-11-02 15:27:49 +00001764}
1765
1766/*
1767 * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1768 */
1769static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1770{
1771 return afs_transfer_reply(call);
1772}
1773
1774/*
1775 * FS.GiveUpAllCallBacks operation type
1776 */
1777static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1778 .name = "FS.GiveUpAllCallBacks",
1779 .deliver = afs_deliver_fs_give_up_all_callbacks,
1780 .destructor = afs_flat_call_destructor,
1781};
1782
1783/*
1784 * Flush all the callbacks we have on a server.
1785 */
David Howellsd2ddc772017-11-02 15:27:50 +00001786int afs_fs_give_up_all_callbacks(struct afs_net *net,
1787 struct afs_server *server,
David Howells8b2a4642017-11-02 15:27:50 +00001788 struct afs_addr_cursor *ac,
David Howellsd2ddc772017-11-02 15:27:50 +00001789 struct key *key)
David Howellsc435ee32017-11-02 15:27:49 +00001790{
1791 struct afs_call *call;
1792 __be32 *bp;
1793
1794 _enter("");
1795
David Howellsd2ddc772017-11-02 15:27:50 +00001796 call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
David Howellsc435ee32017-11-02 15:27:49 +00001797 if (!call)
1798 return -ENOMEM;
1799
1800 call->key = key;
1801
1802 /* marshall the parameters */
1803 bp = call->request;
1804 *bp++ = htonl(FSGIVEUPALLCALLBACKS);
1805
1806 /* Can't take a ref on server */
David Howellsd2ddc772017-11-02 15:27:50 +00001807 return afs_make_call(ac, call, GFP_NOFS, false);
1808}
1809
1810/*
1811 * Deliver reply data to an FS.GetCapabilities operation.
1812 */
1813static int afs_deliver_fs_get_capabilities(struct afs_call *call)
1814{
1815 u32 count;
1816 int ret;
1817
1818 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
1819
1820again:
1821 switch (call->unmarshall) {
1822 case 0:
1823 call->offset = 0;
1824 call->unmarshall++;
1825
1826 /* Extract the capabilities word count */
1827 case 1:
1828 ret = afs_extract_data(call, &call->tmp,
1829 1 * sizeof(__be32),
1830 true);
1831 if (ret < 0)
1832 return ret;
1833
1834 count = ntohl(call->tmp);
1835
1836 call->count = count;
1837 call->count2 = count;
1838 call->offset = 0;
1839 call->unmarshall++;
1840
1841 /* Extract capabilities words */
1842 case 2:
1843 count = min(call->count, 16U);
1844 ret = afs_extract_data(call, call->buffer,
1845 count * sizeof(__be32),
1846 call->count > 16);
1847 if (ret < 0)
1848 return ret;
1849
1850 /* TODO: Examine capabilities */
1851
1852 call->count -= count;
1853 if (call->count > 0)
1854 goto again;
1855 call->offset = 0;
1856 call->unmarshall++;
1857 break;
1858 }
1859
1860 _leave(" = 0 [done]");
1861 return 0;
1862}
1863
1864/*
1865 * FS.GetCapabilities operation type
1866 */
1867static const struct afs_call_type afs_RXFSGetCapabilities = {
1868 .name = "FS.GetCapabilities",
1869 .deliver = afs_deliver_fs_get_capabilities,
1870 .destructor = afs_flat_call_destructor,
1871};
1872
1873/*
1874 * Probe a fileserver for the capabilities that it supports. This can
1875 * return up to 196 words.
1876 */
1877int afs_fs_get_capabilities(struct afs_net *net,
1878 struct afs_server *server,
1879 struct afs_addr_cursor *ac,
1880 struct key *key)
1881{
1882 struct afs_call *call;
1883 __be32 *bp;
1884
1885 _enter("");
1886
1887 call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
1888 if (!call)
1889 return -ENOMEM;
1890
1891 call->key = key;
1892
1893 /* marshall the parameters */
1894 bp = call->request;
1895 *bp++ = htonl(FSGETCAPABILITIES);
1896
1897 /* Can't take a ref on server */
1898 return afs_make_call(ac, call, GFP_NOFS, false);
David Howellse8d6c552007-07-15 23:40:12 -07001899}