blob: 56cc0efa2a0c06d0ffbd8552a2dfab59b9631630 [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>
13#include <linux/sched.h>
David Howells08e0e7c2007-04-26 15:55:03 -070014#include <linux/circ_buf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include "internal.h"
David Howells08e0e7c2007-04-26 15:55:03 -070016#include "afs_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
Linus Torvalds1da177e2005-04-16 15:20:36 -070018/*
David Howells260a9802007-04-26 15:59:35 -070019 * decode an AFSFid block
20 */
21static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
22{
23 const __be32 *bp = *_bp;
24
25 fid->vid = ntohl(*bp++);
26 fid->vnode = ntohl(*bp++);
27 fid->unique = ntohl(*bp++);
28 *_bp = bp;
29}
30
31/*
David Howells08e0e7c2007-04-26 15:55:03 -070032 * decode an AFSFetchStatus block
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 */
David Howells08e0e7c2007-04-26 15:55:03 -070034static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
David Howells260a9802007-04-26 15:59:35 -070035 struct afs_file_status *status,
David Howells31143d52007-05-09 02:33:46 -070036 struct afs_vnode *vnode,
37 afs_dataversion_t *store_version)
Linus Torvalds1da177e2005-04-16 15:20:36 -070038{
David Howells31143d52007-05-09 02:33:46 -070039 afs_dataversion_t expected_version;
David Howells08e0e7c2007-04-26 15:55:03 -070040 const __be32 *bp = *_bp;
41 umode_t mode;
David Howells260a9802007-04-26 15:59:35 -070042 u64 data_version, size;
David Howells08e0e7c2007-04-26 15:55:03 -070043 u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
44
45#define EXTRACT(DST) \
46 do { \
47 u32 x = ntohl(*bp++); \
48 changed |= DST - x; \
49 DST = x; \
50 } while (0)
51
David Howells260a9802007-04-26 15:59:35 -070052 status->if_version = ntohl(*bp++);
53 EXTRACT(status->type);
54 EXTRACT(status->nlink);
55 size = ntohl(*bp++);
David Howells08e0e7c2007-04-26 15:55:03 -070056 data_version = ntohl(*bp++);
David Howells260a9802007-04-26 15:59:35 -070057 EXTRACT(status->author);
58 EXTRACT(status->owner);
59 EXTRACT(status->caller_access); /* call ticket dependent */
60 EXTRACT(status->anon_access);
61 EXTRACT(status->mode);
62 EXTRACT(status->parent.vnode);
63 EXTRACT(status->parent.unique);
David Howells08e0e7c2007-04-26 15:55:03 -070064 bp++; /* seg size */
David Howells260a9802007-04-26 15:59:35 -070065 status->mtime_client = ntohl(*bp++);
66 status->mtime_server = ntohl(*bp++);
67 EXTRACT(status->group);
David Howells08e0e7c2007-04-26 15:55:03 -070068 bp++; /* sync counter */
69 data_version |= (u64) ntohl(*bp++) << 32;
David Howells260a9802007-04-26 15:59:35 -070070 bp++; /* lock count */
71 size |= (u64) ntohl(*bp++) << 32;
72 bp++; /* spare 4 */
David Howells08e0e7c2007-04-26 15:55:03 -070073 *_bp = bp;
74
David Howells260a9802007-04-26 15:59:35 -070075 if (size != status->size) {
76 status->size = size;
77 changed |= true;
David Howells08e0e7c2007-04-26 15:55:03 -070078 }
David Howells260a9802007-04-26 15:59:35 -070079 status->mode &= S_IALLUGO;
David Howells08e0e7c2007-04-26 15:55:03 -070080
81 _debug("vnode time %lx, %lx",
David Howells260a9802007-04-26 15:59:35 -070082 status->mtime_client, status->mtime_server);
David Howells08e0e7c2007-04-26 15:55:03 -070083
David Howells260a9802007-04-26 15:59:35 -070084 if (vnode) {
85 status->parent.vid = vnode->fid.vid;
86 if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
87 _debug("vnode changed");
88 i_size_write(&vnode->vfs_inode, size);
89 vnode->vfs_inode.i_uid = status->owner;
90 vnode->vfs_inode.i_gid = status->group;
91 vnode->vfs_inode.i_version = vnode->fid.unique;
92 vnode->vfs_inode.i_nlink = status->nlink;
93
94 mode = vnode->vfs_inode.i_mode;
95 mode &= ~S_IALLUGO;
96 mode |= status->mode;
97 barrier();
98 vnode->vfs_inode.i_mode = mode;
99 }
100
101 vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server;
102 vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime;
103 vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime;
104 }
105
David Howells31143d52007-05-09 02:33:46 -0700106 expected_version = status->data_version;
107 if (store_version)
108 expected_version = *store_version;
109
110 if (expected_version != data_version) {
David Howells260a9802007-04-26 15:59:35 -0700111 status->data_version = data_version;
112 if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
113 _debug("vnode modified %llx on {%x:%u}",
David S. Millerba3e0e12007-04-26 16:06:22 -0700114 (unsigned long long) data_version,
115 vnode->fid.vid, vnode->fid.vnode);
David Howells260a9802007-04-26 15:59:35 -0700116 set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
117 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
118 }
David Howells31143d52007-05-09 02:33:46 -0700119 } else if (store_version) {
120 status->data_version = data_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 }
David Howellsec268152007-04-26 15:49:28 -0700122}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124/*
David Howells08e0e7c2007-04-26 15:55:03 -0700125 * decode an AFSCallBack block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 */
David Howells08e0e7c2007-04-26 15:55:03 -0700127static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
David Howells08e0e7c2007-04-26 15:55:03 -0700129 const __be32 *bp = *_bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
David Howells08e0e7c2007-04-26 15:55:03 -0700131 vnode->cb_version = ntohl(*bp++);
132 vnode->cb_expiry = ntohl(*bp++);
133 vnode->cb_type = ntohl(*bp++);
134 vnode->cb_expires = vnode->cb_expiry + get_seconds();
135 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700136}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
David Howells260a9802007-04-26 15:59:35 -0700138static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
139 struct afs_callback *cb)
140{
141 const __be32 *bp = *_bp;
142
143 cb->version = ntohl(*bp++);
144 cb->expiry = ntohl(*bp++);
145 cb->type = ntohl(*bp++);
146 *_bp = bp;
147}
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149/*
David Howells08e0e7c2007-04-26 15:55:03 -0700150 * decode an AFSVolSync block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 */
David Howells08e0e7c2007-04-26 15:55:03 -0700152static void xdr_decode_AFSVolSync(const __be32 **_bp,
153 struct afs_volsync *volsync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
David Howells08e0e7c2007-04-26 15:55:03 -0700155 const __be32 *bp = *_bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
David Howells08e0e7c2007-04-26 15:55:03 -0700157 volsync->creation = ntohl(*bp++);
158 bp++; /* spare2 */
159 bp++; /* spare3 */
160 bp++; /* spare4 */
161 bp++; /* spare5 */
162 bp++; /* spare6 */
163 *_bp = bp;
David Howellsec268152007-04-26 15:49:28 -0700164}
David Howells08e0e7c2007-04-26 15:55:03 -0700165
166/*
David Howells31143d52007-05-09 02:33:46 -0700167 * encode the requested attributes into an AFSStoreStatus block
168 */
169static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
170{
171 __be32 *bp = *_bp;
172 u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
173
174 mask = 0;
175 if (attr->ia_valid & ATTR_MTIME) {
176 mask |= AFS_SET_MTIME;
177 mtime = attr->ia_mtime.tv_sec;
178 }
179
180 if (attr->ia_valid & ATTR_UID) {
181 mask |= AFS_SET_OWNER;
182 owner = attr->ia_uid;
183 }
184
185 if (attr->ia_valid & ATTR_GID) {
186 mask |= AFS_SET_GROUP;
187 group = attr->ia_gid;
188 }
189
190 if (attr->ia_valid & ATTR_MODE) {
191 mask |= AFS_SET_MODE;
192 mode = attr->ia_mode & S_IALLUGO;
193 }
194
195 *bp++ = htonl(mask);
196 *bp++ = htonl(mtime);
197 *bp++ = htonl(owner);
198 *bp++ = htonl(group);
199 *bp++ = htonl(mode);
200 *bp++ = 0; /* segment size */
201 *_bp = bp;
202}
203
204/*
David Howells08e0e7c2007-04-26 15:55:03 -0700205 * deliver reply data to an FS.FetchStatus
206 */
207static int afs_deliver_fs_fetch_status(struct afs_call *call,
208 struct sk_buff *skb, bool last)
209{
David Howells260a9802007-04-26 15:59:35 -0700210 struct afs_vnode *vnode = call->reply;
David Howells08e0e7c2007-04-26 15:55:03 -0700211 const __be32 *bp;
212
213 _enter(",,%u", last);
214
215 afs_transfer_reply(call, skb);
216 if (!last)
217 return 0;
218
219 if (call->reply_size != call->reply_max)
220 return -EBADMSG;
221
222 /* unmarshall the reply once we've received all of it */
223 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700224 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700225 xdr_decode_AFSCallBack(&bp, vnode);
David Howells08e0e7c2007-04-26 15:55:03 -0700226 if (call->reply2)
227 xdr_decode_AFSVolSync(&bp, call->reply2);
228
229 _leave(" = 0 [done]");
230 return 0;
231}
232
233/*
234 * FS.FetchStatus operation type
235 */
236static const struct afs_call_type afs_RXFSFetchStatus = {
David Howells00d3b7a2007-04-26 15:57:07 -0700237 .name = "FS.FetchStatus",
David Howells08e0e7c2007-04-26 15:55:03 -0700238 .deliver = afs_deliver_fs_fetch_status,
239 .abort_to_error = afs_abort_to_error,
240 .destructor = afs_flat_call_destructor,
241};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243/*
244 * fetch the status information for a file
245 */
David Howells08e0e7c2007-04-26 15:55:03 -0700246int afs_fs_fetch_file_status(struct afs_server *server,
David Howells00d3b7a2007-04-26 15:57:07 -0700247 struct key *key,
David Howells08e0e7c2007-04-26 15:55:03 -0700248 struct afs_vnode *vnode,
249 struct afs_volsync *volsync,
250 const struct afs_wait_mode *wait_mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251{
David Howells08e0e7c2007-04-26 15:55:03 -0700252 struct afs_call *call;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 __be32 *bp;
254
David Howells416351f2007-05-09 02:33:45 -0700255 _enter(",%x,{%x:%u},,",
David Howells260a9802007-04-26 15:59:35 -0700256 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
David Howells260a9802007-04-26 15:59:35 -0700258 call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700259 if (!call)
260 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
David Howells00d3b7a2007-04-26 15:57:07 -0700262 call->key = key;
David Howells08e0e7c2007-04-26 15:55:03 -0700263 call->reply = vnode;
264 call->reply2 = volsync;
265 call->service_id = FS_SERVICE;
266 call->port = htons(AFS_FS_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700269 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 bp[0] = htonl(FSFETCHSTATUS);
271 bp[1] = htonl(vnode->fid.vid);
272 bp[2] = htonl(vnode->fid.vnode);
273 bp[3] = htonl(vnode->fid.unique);
274
David Howells08e0e7c2007-04-26 15:55:03 -0700275 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
David Howellsec268152007-04-26 15:49:28 -0700276}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278/*
David Howells08e0e7c2007-04-26 15:55:03 -0700279 * deliver reply data to an FS.FetchData
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 */
David Howells08e0e7c2007-04-26 15:55:03 -0700281static int afs_deliver_fs_fetch_data(struct afs_call *call,
282 struct sk_buff *skb, bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
David Howells260a9802007-04-26 15:59:35 -0700284 struct afs_vnode *vnode = call->reply;
David Howells08e0e7c2007-04-26 15:55:03 -0700285 const __be32 *bp;
286 struct page *page;
287 void *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700289
290 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
291
292 switch (call->unmarshall) {
293 case 0:
294 call->offset = 0;
295 call->unmarshall++;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700296 if (call->operation_ID != FSFETCHDATA64) {
297 call->unmarshall++;
298 goto no_msw;
299 }
David Howells08e0e7c2007-04-26 15:55:03 -0700300
David Howellsb9b1f8d2007-05-10 03:15:21 -0700301 /* extract the upper part of the returned data length of an
302 * FSFETCHDATA64 op (which should always be 0 using this
303 * client) */
David Howells08e0e7c2007-04-26 15:55:03 -0700304 case 1:
David Howellsb9b1f8d2007-05-10 03:15:21 -0700305 _debug("extract data length (MSW)");
306 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
307 switch (ret) {
308 case 0: break;
309 case -EAGAIN: return 0;
310 default: return ret;
311 }
312
313 call->count = ntohl(call->tmp);
314 _debug("DATA length MSW: %u", call->count);
315 if (call->count > 0)
316 return -EBADMSG;
317 call->offset = 0;
318 call->unmarshall++;
319
320 no_msw:
321 /* extract the returned data length */
322 case 2:
David Howells08e0e7c2007-04-26 15:55:03 -0700323 _debug("extract data length");
324 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
325 switch (ret) {
326 case 0: break;
327 case -EAGAIN: return 0;
328 default: return ret;
329 }
330
331 call->count = ntohl(call->tmp);
332 _debug("DATA length: %u", call->count);
333 if (call->count > PAGE_SIZE)
334 return -EBADMSG;
335 call->offset = 0;
336 call->unmarshall++;
337
David Howells08e0e7c2007-04-26 15:55:03 -0700338 /* extract the returned data */
David Howellsb9b1f8d2007-05-10 03:15:21 -0700339 case 3:
David Howells08e0e7c2007-04-26 15:55:03 -0700340 _debug("extract data");
David Howells416351f2007-05-09 02:33:45 -0700341 if (call->count > 0) {
342 page = call->reply3;
343 buffer = kmap_atomic(page, KM_USER0);
344 ret = afs_extract_data(call, skb, last, buffer,
345 call->count);
346 kunmap_atomic(buffer, KM_USER0);
347 switch (ret) {
348 case 0: break;
349 case -EAGAIN: return 0;
350 default: return ret;
351 }
David Howells08e0e7c2007-04-26 15:55:03 -0700352 }
353
354 call->offset = 0;
355 call->unmarshall++;
356
357 /* extract the metadata */
David Howellsb9b1f8d2007-05-10 03:15:21 -0700358 case 4:
David Howells260a9802007-04-26 15:59:35 -0700359 ret = afs_extract_data(call, skb, last, call->buffer,
360 (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700361 switch (ret) {
362 case 0: break;
363 case -EAGAIN: return 0;
364 default: return ret;
365 }
366
367 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700368 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700369 xdr_decode_AFSCallBack(&bp, vnode);
David Howells08e0e7c2007-04-26 15:55:03 -0700370 if (call->reply2)
371 xdr_decode_AFSVolSync(&bp, call->reply2);
372
373 call->offset = 0;
374 call->unmarshall++;
375
David Howellsb9b1f8d2007-05-10 03:15:21 -0700376 case 5:
David Howells08e0e7c2007-04-26 15:55:03 -0700377 _debug("trailer");
378 if (skb->len != 0)
379 return -EBADMSG;
380 break;
381 }
382
383 if (!last)
384 return 0;
385
David Howells416351f2007-05-09 02:33:45 -0700386 if (call->count < PAGE_SIZE) {
387 _debug("clear");
388 page = call->reply3;
389 buffer = kmap_atomic(page, KM_USER0);
390 memset(buffer + call->count, 0, PAGE_SIZE - call->count);
391 kunmap_atomic(buffer, KM_USER0);
392 }
393
David Howells08e0e7c2007-04-26 15:55:03 -0700394 _leave(" = 0 [done]");
395 return 0;
396}
397
398/*
399 * FS.FetchData operation type
400 */
401static const struct afs_call_type afs_RXFSFetchData = {
David Howells00d3b7a2007-04-26 15:57:07 -0700402 .name = "FS.FetchData",
David Howells08e0e7c2007-04-26 15:55:03 -0700403 .deliver = afs_deliver_fs_fetch_data,
404 .abort_to_error = afs_abort_to_error,
405 .destructor = afs_flat_call_destructor,
406};
407
David Howellsb9b1f8d2007-05-10 03:15:21 -0700408static const struct afs_call_type afs_RXFSFetchData64 = {
409 .name = "FS.FetchData64",
410 .deliver = afs_deliver_fs_fetch_data,
411 .abort_to_error = afs_abort_to_error,
412 .destructor = afs_flat_call_destructor,
413};
414
415/*
416 * fetch data from a very large file
417 */
418static int afs_fs_fetch_data64(struct afs_server *server,
419 struct key *key,
420 struct afs_vnode *vnode,
421 off_t offset, size_t length,
422 struct page *buffer,
423 const struct afs_wait_mode *wait_mode)
424{
425 struct afs_call *call;
426 __be32 *bp;
427
428 _enter("");
429
430 ASSERTCMP(length, <, ULONG_MAX);
431
432 call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
433 if (!call)
434 return -ENOMEM;
435
436 call->key = key;
437 call->reply = vnode;
438 call->reply2 = NULL; /* volsync */
439 call->reply3 = buffer;
440 call->service_id = FS_SERVICE;
441 call->port = htons(AFS_FS_PORT);
442 call->operation_ID = FSFETCHDATA64;
443
444 /* marshall the parameters */
445 bp = call->request;
446 bp[0] = htonl(FSFETCHDATA64);
447 bp[1] = htonl(vnode->fid.vid);
448 bp[2] = htonl(vnode->fid.vnode);
449 bp[3] = htonl(vnode->fid.unique);
450 bp[4] = htonl(upper_32_bits(offset));
451 bp[5] = htonl((u32) offset);
452 bp[6] = 0;
453 bp[7] = htonl((u32) length);
454
455 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
456}
457
David Howells08e0e7c2007-04-26 15:55:03 -0700458/*
459 * fetch data from a file
460 */
461int afs_fs_fetch_data(struct afs_server *server,
David Howells00d3b7a2007-04-26 15:57:07 -0700462 struct key *key,
David Howells08e0e7c2007-04-26 15:55:03 -0700463 struct afs_vnode *vnode,
464 off_t offset, size_t length,
465 struct page *buffer,
David Howells08e0e7c2007-04-26 15:55:03 -0700466 const struct afs_wait_mode *wait_mode)
467{
468 struct afs_call *call;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 __be32 *bp;
470
David Howellsb9b1f8d2007-05-10 03:15:21 -0700471 if (upper_32_bits(offset) || upper_32_bits(offset + length))
472 return afs_fs_fetch_data64(server, key, vnode, offset, length,
473 buffer, wait_mode);
474
David Howells08e0e7c2007-04-26 15:55:03 -0700475 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
David Howells260a9802007-04-26 15:59:35 -0700477 call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700478 if (!call)
479 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
David Howells00d3b7a2007-04-26 15:57:07 -0700481 call->key = key;
David Howells08e0e7c2007-04-26 15:55:03 -0700482 call->reply = vnode;
David Howells260a9802007-04-26 15:59:35 -0700483 call->reply2 = NULL; /* volsync */
David Howells08e0e7c2007-04-26 15:55:03 -0700484 call->reply3 = buffer;
485 call->service_id = FS_SERVICE;
486 call->port = htons(AFS_FS_PORT);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700487 call->operation_ID = FSFETCHDATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700490 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 bp[0] = htonl(FSFETCHDATA);
David Howells08e0e7c2007-04-26 15:55:03 -0700492 bp[1] = htonl(vnode->fid.vid);
493 bp[2] = htonl(vnode->fid.vnode);
494 bp[3] = htonl(vnode->fid.unique);
495 bp[4] = htonl(offset);
496 bp[5] = htonl(length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
David Howells08e0e7c2007-04-26 15:55:03 -0700498 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
David Howellsec268152007-04-26 15:49:28 -0700499}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501/*
David Howells08e0e7c2007-04-26 15:55:03 -0700502 * deliver reply data to an FS.GiveUpCallBacks
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 */
David Howells08e0e7c2007-04-26 15:55:03 -0700504static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
505 struct sk_buff *skb, bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
David Howells08e0e7c2007-04-26 15:55:03 -0700507 _enter(",{%u},%d", skb->len, last);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
David Howells08e0e7c2007-04-26 15:55:03 -0700509 if (skb->len > 0)
510 return -EBADMSG; /* shouldn't be any reply data */
511 return 0;
512}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
David Howells08e0e7c2007-04-26 15:55:03 -0700514/*
515 * FS.GiveUpCallBacks operation type
516 */
517static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
David Howells00d3b7a2007-04-26 15:57:07 -0700518 .name = "FS.GiveUpCallBacks",
David Howells08e0e7c2007-04-26 15:55:03 -0700519 .deliver = afs_deliver_fs_give_up_callbacks,
520 .abort_to_error = afs_abort_to_error,
521 .destructor = afs_flat_call_destructor,
522};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
David Howells08e0e7c2007-04-26 15:55:03 -0700524/*
525 * give up a set of callbacks
526 * - the callbacks are held in the server->cb_break ring
527 */
528int afs_fs_give_up_callbacks(struct afs_server *server,
529 const struct afs_wait_mode *wait_mode)
530{
531 struct afs_call *call;
532 size_t ncallbacks;
533 __be32 *bp, *tp;
534 int loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
David Howells08e0e7c2007-04-26 15:55:03 -0700536 ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
537 ARRAY_SIZE(server->cb_break));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
David Howells08e0e7c2007-04-26 15:55:03 -0700539 _enter("{%zu},", ncallbacks);
540
541 if (ncallbacks == 0)
542 return 0;
543 if (ncallbacks > AFSCBMAX)
544 ncallbacks = AFSCBMAX;
545
546 _debug("break %zu callbacks", ncallbacks);
547
548 call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
549 12 + ncallbacks * 6 * 4, 0);
550 if (!call)
551 return -ENOMEM;
552
553 call->service_id = FS_SERVICE;
554 call->port = htons(AFS_FS_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700557 bp = call->request;
558 tp = bp + 2 + ncallbacks * 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 *bp++ = htonl(FSGIVEUPCALLBACKS);
David Howells08e0e7c2007-04-26 15:55:03 -0700560 *bp++ = htonl(ncallbacks);
561 *tp++ = htonl(ncallbacks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
David Howells08e0e7c2007-04-26 15:55:03 -0700563 atomic_sub(ncallbacks, &server->cb_break_n);
564 for (loop = ncallbacks; loop > 0; loop--) {
565 struct afs_callback *cb =
566 &server->cb_break[server->cb_break_tail];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
David Howells08e0e7c2007-04-26 15:55:03 -0700568 *bp++ = htonl(cb->fid.vid);
569 *bp++ = htonl(cb->fid.vnode);
570 *bp++ = htonl(cb->fid.unique);
571 *tp++ = htonl(cb->version);
572 *tp++ = htonl(cb->expiry);
573 *tp++ = htonl(cb->type);
574 smp_mb();
575 server->cb_break_tail =
576 (server->cb_break_tail + 1) &
577 (ARRAY_SIZE(server->cb_break) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 }
579
David Howells08e0e7c2007-04-26 15:55:03 -0700580 ASSERT(ncallbacks > 0);
581 wake_up_nr(&server->cb_break_waitq, ncallbacks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
David Howells08e0e7c2007-04-26 15:55:03 -0700583 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
David Howellsec268152007-04-26 15:49:28 -0700584}
David Howells260a9802007-04-26 15:59:35 -0700585
586/*
587 * deliver reply data to an FS.CreateFile or an FS.MakeDir
588 */
589static int afs_deliver_fs_create_vnode(struct afs_call *call,
590 struct sk_buff *skb, bool last)
591{
592 struct afs_vnode *vnode = call->reply;
593 const __be32 *bp;
594
595 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
596
597 afs_transfer_reply(call, skb);
598 if (!last)
599 return 0;
600
601 if (call->reply_size != call->reply_max)
602 return -EBADMSG;
603
604 /* unmarshall the reply once we've received all of it */
605 bp = call->buffer;
606 xdr_decode_AFSFid(&bp, call->reply2);
David Howells31143d52007-05-09 02:33:46 -0700607 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
608 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700609 xdr_decode_AFSCallBack_raw(&bp, call->reply4);
610 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
611
612 _leave(" = 0 [done]");
613 return 0;
614}
615
616/*
617 * FS.CreateFile and FS.MakeDir operation type
618 */
619static const struct afs_call_type afs_RXFSCreateXXXX = {
620 .name = "FS.CreateXXXX",
621 .deliver = afs_deliver_fs_create_vnode,
622 .abort_to_error = afs_abort_to_error,
623 .destructor = afs_flat_call_destructor,
624};
625
626/*
627 * create a file or make a directory
628 */
629int afs_fs_create(struct afs_server *server,
630 struct key *key,
631 struct afs_vnode *vnode,
632 const char *name,
633 umode_t mode,
634 struct afs_fid *newfid,
635 struct afs_file_status *newstatus,
636 struct afs_callback *newcb,
637 const struct afs_wait_mode *wait_mode)
638{
639 struct afs_call *call;
640 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
649 call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
650 (3 + 21 + 21 + 3 + 6) * 4);
651 if (!call)
652 return -ENOMEM;
653
654 call->key = key;
655 call->reply = vnode;
656 call->reply2 = newfid;
657 call->reply3 = newstatus;
658 call->reply4 = newcb;
659 call->service_id = FS_SERVICE;
660 call->port = htons(AFS_FS_PORT);
661
662 /* marshall the parameters */
663 bp = call->request;
664 *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
665 *bp++ = htonl(vnode->fid.vid);
666 *bp++ = htonl(vnode->fid.vnode);
667 *bp++ = htonl(vnode->fid.unique);
668 *bp++ = htonl(namesz);
669 memcpy(bp, name, namesz);
670 bp = (void *) bp + namesz;
671 if (padsz > 0) {
672 memset(bp, 0, padsz);
673 bp = (void *) bp + padsz;
674 }
675 *bp++ = htonl(AFS_SET_MODE);
676 *bp++ = 0; /* mtime */
677 *bp++ = 0; /* owner */
678 *bp++ = 0; /* group */
679 *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
680 *bp++ = 0; /* segment size */
681
682 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
683}
684
685/*
686 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
687 */
688static int afs_deliver_fs_remove(struct afs_call *call,
689 struct sk_buff *skb, bool last)
690{
691 struct afs_vnode *vnode = call->reply;
692 const __be32 *bp;
693
694 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
695
696 afs_transfer_reply(call, skb);
697 if (!last)
698 return 0;
699
700 if (call->reply_size != call->reply_max)
701 return -EBADMSG;
702
703 /* unmarshall the reply once we've received all of it */
704 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700705 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700706 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
707
708 _leave(" = 0 [done]");
709 return 0;
710}
711
712/*
713 * FS.RemoveDir/FS.RemoveFile operation type
714 */
715static const struct afs_call_type afs_RXFSRemoveXXXX = {
716 .name = "FS.RemoveXXXX",
717 .deliver = afs_deliver_fs_remove,
718 .abort_to_error = afs_abort_to_error,
719 .destructor = afs_flat_call_destructor,
720};
721
722/*
723 * remove a file or directory
724 */
725int afs_fs_remove(struct afs_server *server,
726 struct key *key,
727 struct afs_vnode *vnode,
728 const char *name,
729 bool isdir,
730 const struct afs_wait_mode *wait_mode)
731{
732 struct afs_call *call;
733 size_t namesz, reqsz, padsz;
734 __be32 *bp;
735
736 _enter("");
737
738 namesz = strlen(name);
739 padsz = (4 - (namesz & 3)) & 3;
740 reqsz = (5 * 4) + namesz + padsz;
741
742 call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
743 if (!call)
744 return -ENOMEM;
745
746 call->key = key;
747 call->reply = vnode;
748 call->service_id = FS_SERVICE;
749 call->port = htons(AFS_FS_PORT);
750
751 /* marshall the parameters */
752 bp = call->request;
753 *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
754 *bp++ = htonl(vnode->fid.vid);
755 *bp++ = htonl(vnode->fid.vnode);
756 *bp++ = htonl(vnode->fid.unique);
757 *bp++ = htonl(namesz);
758 memcpy(bp, name, namesz);
759 bp = (void *) bp + namesz;
760 if (padsz > 0) {
761 memset(bp, 0, padsz);
762 bp = (void *) bp + padsz;
763 }
764
765 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
766}
767
768/*
769 * deliver reply data to an FS.Link
770 */
771static int afs_deliver_fs_link(struct afs_call *call,
772 struct sk_buff *skb, bool last)
773{
774 struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
775 const __be32 *bp;
776
777 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
778
779 afs_transfer_reply(call, skb);
780 if (!last)
781 return 0;
782
783 if (call->reply_size != call->reply_max)
784 return -EBADMSG;
785
786 /* unmarshall the reply once we've received all of it */
787 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700788 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
789 xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700790 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
791
792 _leave(" = 0 [done]");
793 return 0;
794}
795
796/*
797 * FS.Link operation type
798 */
799static const struct afs_call_type afs_RXFSLink = {
800 .name = "FS.Link",
801 .deliver = afs_deliver_fs_link,
802 .abort_to_error = afs_abort_to_error,
803 .destructor = afs_flat_call_destructor,
804};
805
806/*
807 * make a hard link
808 */
809int afs_fs_link(struct afs_server *server,
810 struct key *key,
811 struct afs_vnode *dvnode,
812 struct afs_vnode *vnode,
813 const char *name,
814 const struct afs_wait_mode *wait_mode)
815{
816 struct afs_call *call;
817 size_t namesz, reqsz, padsz;
818 __be32 *bp;
819
820 _enter("");
821
822 namesz = strlen(name);
823 padsz = (4 - (namesz & 3)) & 3;
824 reqsz = (5 * 4) + namesz + padsz + (3 * 4);
825
826 call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
827 if (!call)
828 return -ENOMEM;
829
830 call->key = key;
831 call->reply = dvnode;
832 call->reply2 = vnode;
833 call->service_id = FS_SERVICE;
834 call->port = htons(AFS_FS_PORT);
835
836 /* marshall the parameters */
837 bp = call->request;
838 *bp++ = htonl(FSLINK);
839 *bp++ = htonl(dvnode->fid.vid);
840 *bp++ = htonl(dvnode->fid.vnode);
841 *bp++ = htonl(dvnode->fid.unique);
842 *bp++ = htonl(namesz);
843 memcpy(bp, name, namesz);
844 bp = (void *) bp + namesz;
845 if (padsz > 0) {
846 memset(bp, 0, padsz);
847 bp = (void *) bp + padsz;
848 }
849 *bp++ = htonl(vnode->fid.vid);
850 *bp++ = htonl(vnode->fid.vnode);
851 *bp++ = htonl(vnode->fid.unique);
852
853 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
854}
855
856/*
857 * deliver reply data to an FS.Symlink
858 */
859static int afs_deliver_fs_symlink(struct afs_call *call,
860 struct sk_buff *skb, bool last)
861{
862 struct afs_vnode *vnode = call->reply;
863 const __be32 *bp;
864
865 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
866
867 afs_transfer_reply(call, skb);
868 if (!last)
869 return 0;
870
871 if (call->reply_size != call->reply_max)
872 return -EBADMSG;
873
874 /* unmarshall the reply once we've received all of it */
875 bp = call->buffer;
876 xdr_decode_AFSFid(&bp, call->reply2);
David Howells31143d52007-05-09 02:33:46 -0700877 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
878 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700879 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
880
881 _leave(" = 0 [done]");
882 return 0;
883}
884
885/*
886 * FS.Symlink operation type
887 */
888static const struct afs_call_type afs_RXFSSymlink = {
889 .name = "FS.Symlink",
890 .deliver = afs_deliver_fs_symlink,
891 .abort_to_error = afs_abort_to_error,
892 .destructor = afs_flat_call_destructor,
893};
894
895/*
896 * create a symbolic link
897 */
898int afs_fs_symlink(struct afs_server *server,
899 struct key *key,
900 struct afs_vnode *vnode,
901 const char *name,
902 const char *contents,
903 struct afs_fid *newfid,
904 struct afs_file_status *newstatus,
905 const struct afs_wait_mode *wait_mode)
906{
907 struct afs_call *call;
908 size_t namesz, reqsz, padsz, c_namesz, c_padsz;
909 __be32 *bp;
910
911 _enter("");
912
913 namesz = strlen(name);
914 padsz = (4 - (namesz & 3)) & 3;
915
916 c_namesz = strlen(contents);
917 c_padsz = (4 - (c_namesz & 3)) & 3;
918
919 reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
920
921 call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
922 (3 + 21 + 21 + 6) * 4);
923 if (!call)
924 return -ENOMEM;
925
926 call->key = key;
927 call->reply = vnode;
928 call->reply2 = newfid;
929 call->reply3 = newstatus;
930 call->service_id = FS_SERVICE;
931 call->port = htons(AFS_FS_PORT);
932
933 /* marshall the parameters */
934 bp = call->request;
935 *bp++ = htonl(FSSYMLINK);
936 *bp++ = htonl(vnode->fid.vid);
937 *bp++ = htonl(vnode->fid.vnode);
938 *bp++ = htonl(vnode->fid.unique);
939 *bp++ = htonl(namesz);
940 memcpy(bp, name, namesz);
941 bp = (void *) bp + namesz;
942 if (padsz > 0) {
943 memset(bp, 0, padsz);
944 bp = (void *) bp + padsz;
945 }
946 *bp++ = htonl(c_namesz);
947 memcpy(bp, contents, c_namesz);
948 bp = (void *) bp + c_namesz;
949 if (c_padsz > 0) {
950 memset(bp, 0, c_padsz);
951 bp = (void *) bp + c_padsz;
952 }
953 *bp++ = htonl(AFS_SET_MODE);
954 *bp++ = 0; /* mtime */
955 *bp++ = 0; /* owner */
956 *bp++ = 0; /* group */
957 *bp++ = htonl(S_IRWXUGO); /* unix mode */
958 *bp++ = 0; /* segment size */
959
960 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
961}
962
963/*
964 * deliver reply data to an FS.Rename
965 */
966static int afs_deliver_fs_rename(struct afs_call *call,
967 struct sk_buff *skb, bool last)
968{
969 struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
970 const __be32 *bp;
971
972 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
973
974 afs_transfer_reply(call, skb);
975 if (!last)
976 return 0;
977
978 if (call->reply_size != call->reply_max)
979 return -EBADMSG;
980
981 /* unmarshall the reply once we've received all of it */
982 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700983 xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700984 if (new_dvnode != orig_dvnode)
David Howells31143d52007-05-09 02:33:46 -0700985 xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
986 NULL);
David Howells260a9802007-04-26 15:59:35 -0700987 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
988
989 _leave(" = 0 [done]");
990 return 0;
991}
992
993/*
994 * FS.Rename operation type
995 */
996static const struct afs_call_type afs_RXFSRename = {
997 .name = "FS.Rename",
998 .deliver = afs_deliver_fs_rename,
999 .abort_to_error = afs_abort_to_error,
1000 .destructor = afs_flat_call_destructor,
1001};
1002
1003/*
1004 * create a symbolic link
1005 */
1006int afs_fs_rename(struct afs_server *server,
1007 struct key *key,
1008 struct afs_vnode *orig_dvnode,
1009 const char *orig_name,
1010 struct afs_vnode *new_dvnode,
1011 const char *new_name,
1012 const struct afs_wait_mode *wait_mode)
1013{
1014 struct afs_call *call;
1015 size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1016 __be32 *bp;
1017
1018 _enter("");
1019
1020 o_namesz = strlen(orig_name);
1021 o_padsz = (4 - (o_namesz & 3)) & 3;
1022
1023 n_namesz = strlen(new_name);
1024 n_padsz = (4 - (n_namesz & 3)) & 3;
1025
1026 reqsz = (4 * 4) +
1027 4 + o_namesz + o_padsz +
1028 (3 * 4) +
1029 4 + n_namesz + n_padsz;
1030
1031 call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1032 if (!call)
1033 return -ENOMEM;
1034
1035 call->key = key;
1036 call->reply = orig_dvnode;
1037 call->reply2 = new_dvnode;
1038 call->service_id = FS_SERVICE;
1039 call->port = htons(AFS_FS_PORT);
1040
1041 /* marshall the parameters */
1042 bp = call->request;
1043 *bp++ = htonl(FSRENAME);
1044 *bp++ = htonl(orig_dvnode->fid.vid);
1045 *bp++ = htonl(orig_dvnode->fid.vnode);
1046 *bp++ = htonl(orig_dvnode->fid.unique);
1047 *bp++ = htonl(o_namesz);
1048 memcpy(bp, orig_name, o_namesz);
1049 bp = (void *) bp + o_namesz;
1050 if (o_padsz > 0) {
1051 memset(bp, 0, o_padsz);
1052 bp = (void *) bp + o_padsz;
1053 }
1054
1055 *bp++ = htonl(new_dvnode->fid.vid);
1056 *bp++ = htonl(new_dvnode->fid.vnode);
1057 *bp++ = htonl(new_dvnode->fid.unique);
1058 *bp++ = htonl(n_namesz);
1059 memcpy(bp, new_name, n_namesz);
1060 bp = (void *) bp + n_namesz;
1061 if (n_padsz > 0) {
1062 memset(bp, 0, n_padsz);
1063 bp = (void *) bp + n_padsz;
1064 }
1065
1066 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1067}
David Howells31143d52007-05-09 02:33:46 -07001068
1069/*
1070 * deliver reply data to an FS.StoreData
1071 */
1072static int afs_deliver_fs_store_data(struct afs_call *call,
1073 struct sk_buff *skb, bool last)
1074{
1075 struct afs_vnode *vnode = call->reply;
1076 const __be32 *bp;
1077
1078 _enter(",,%u", last);
1079
1080 afs_transfer_reply(call, skb);
1081 if (!last) {
1082 _leave(" = 0 [more]");
1083 return 0;
1084 }
1085
1086 if (call->reply_size != call->reply_max) {
1087 _leave(" = -EBADMSG [%u != %u]",
1088 call->reply_size, call->reply_max);
1089 return -EBADMSG;
1090 }
1091
1092 /* unmarshall the reply once we've received all of it */
1093 bp = call->buffer;
1094 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
1095 &call->store_version);
1096 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1097
1098 afs_pages_written_back(vnode, call);
1099
1100 _leave(" = 0 [done]");
1101 return 0;
1102}
1103
1104/*
1105 * FS.StoreData operation type
1106 */
1107static const struct afs_call_type afs_RXFSStoreData = {
1108 .name = "FS.StoreData",
1109 .deliver = afs_deliver_fs_store_data,
1110 .abort_to_error = afs_abort_to_error,
1111 .destructor = afs_flat_call_destructor,
1112};
1113
David Howellsb9b1f8d2007-05-10 03:15:21 -07001114static const struct afs_call_type afs_RXFSStoreData64 = {
1115 .name = "FS.StoreData64",
1116 .deliver = afs_deliver_fs_store_data,
1117 .abort_to_error = afs_abort_to_error,
1118 .destructor = afs_flat_call_destructor,
1119};
1120
1121/*
1122 * store a set of pages to a very large file
1123 */
1124static int afs_fs_store_data64(struct afs_server *server,
1125 struct afs_writeback *wb,
1126 pgoff_t first, pgoff_t last,
1127 unsigned offset, unsigned to,
1128 loff_t size, loff_t pos, loff_t i_size,
1129 const struct afs_wait_mode *wait_mode)
1130{
1131 struct afs_vnode *vnode = wb->vnode;
1132 struct afs_call *call;
1133 __be32 *bp;
1134
1135 _enter(",%x,{%x:%u},,",
1136 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1137
1138 call = afs_alloc_flat_call(&afs_RXFSStoreData64,
1139 (4 + 6 + 3 * 2) * 4,
1140 (21 + 6) * 4);
1141 if (!call)
1142 return -ENOMEM;
1143
1144 call->wb = wb;
1145 call->key = wb->key;
1146 call->reply = vnode;
1147 call->service_id = FS_SERVICE;
1148 call->port = htons(AFS_FS_PORT);
1149 call->mapping = vnode->vfs_inode.i_mapping;
1150 call->first = first;
1151 call->last = last;
1152 call->first_offset = offset;
1153 call->last_to = to;
1154 call->send_pages = true;
1155 call->store_version = vnode->status.data_version + 1;
1156
1157 /* marshall the parameters */
1158 bp = call->request;
1159 *bp++ = htonl(FSSTOREDATA64);
1160 *bp++ = htonl(vnode->fid.vid);
1161 *bp++ = htonl(vnode->fid.vnode);
1162 *bp++ = htonl(vnode->fid.unique);
1163
1164 *bp++ = 0; /* mask */
1165 *bp++ = 0; /* mtime */
1166 *bp++ = 0; /* owner */
1167 *bp++ = 0; /* group */
1168 *bp++ = 0; /* unix mode */
1169 *bp++ = 0; /* segment size */
1170
1171 *bp++ = htonl(pos >> 32);
1172 *bp++ = htonl((u32) pos);
1173 *bp++ = htonl(size >> 32);
1174 *bp++ = htonl((u32) size);
1175 *bp++ = htonl(i_size >> 32);
1176 *bp++ = htonl((u32) i_size);
1177
1178 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1179}
1180
David Howells31143d52007-05-09 02:33:46 -07001181/*
1182 * store a set of pages
1183 */
1184int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
1185 pgoff_t first, pgoff_t last,
1186 unsigned offset, unsigned to,
1187 const struct afs_wait_mode *wait_mode)
1188{
1189 struct afs_vnode *vnode = wb->vnode;
1190 struct afs_call *call;
1191 loff_t size, pos, i_size;
1192 __be32 *bp;
1193
1194 _enter(",%x,{%x:%u},,",
1195 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1196
1197 size = to - offset;
1198 if (first != last)
1199 size += (loff_t)(last - first) << PAGE_SHIFT;
1200 pos = (loff_t)first << PAGE_SHIFT;
1201 pos += offset;
1202
1203 i_size = i_size_read(&vnode->vfs_inode);
1204 if (pos + size > i_size)
1205 i_size = size + pos;
1206
1207 _debug("size %llx, at %llx, i_size %llx",
1208 (unsigned long long) size, (unsigned long long) pos,
1209 (unsigned long long) i_size);
1210
David Howellsb9b1f8d2007-05-10 03:15:21 -07001211 if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
1212 return afs_fs_store_data64(server, wb, first, last, offset, to,
1213 size, pos, i_size, wait_mode);
David Howells31143d52007-05-09 02:33:46 -07001214
1215 call = afs_alloc_flat_call(&afs_RXFSStoreData,
1216 (4 + 6 + 3) * 4,
1217 (21 + 6) * 4);
1218 if (!call)
1219 return -ENOMEM;
1220
1221 call->wb = wb;
1222 call->key = wb->key;
1223 call->reply = vnode;
1224 call->service_id = FS_SERVICE;
1225 call->port = htons(AFS_FS_PORT);
1226 call->mapping = vnode->vfs_inode.i_mapping;
1227 call->first = first;
1228 call->last = last;
1229 call->first_offset = offset;
1230 call->last_to = to;
1231 call->send_pages = true;
1232 call->store_version = vnode->status.data_version + 1;
1233
1234 /* marshall the parameters */
1235 bp = call->request;
1236 *bp++ = htonl(FSSTOREDATA);
1237 *bp++ = htonl(vnode->fid.vid);
1238 *bp++ = htonl(vnode->fid.vnode);
1239 *bp++ = htonl(vnode->fid.unique);
1240
1241 *bp++ = 0; /* mask */
1242 *bp++ = 0; /* mtime */
1243 *bp++ = 0; /* owner */
1244 *bp++ = 0; /* group */
1245 *bp++ = 0; /* unix mode */
1246 *bp++ = 0; /* segment size */
1247
1248 *bp++ = htonl(pos);
1249 *bp++ = htonl(size);
1250 *bp++ = htonl(i_size);
1251
1252 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1253}
1254
1255/*
1256 * deliver reply data to an FS.StoreStatus
1257 */
1258static int afs_deliver_fs_store_status(struct afs_call *call,
1259 struct sk_buff *skb, bool last)
1260{
1261 afs_dataversion_t *store_version;
1262 struct afs_vnode *vnode = call->reply;
1263 const __be32 *bp;
1264
1265 _enter(",,%u", last);
1266
1267 afs_transfer_reply(call, skb);
1268 if (!last) {
1269 _leave(" = 0 [more]");
1270 return 0;
1271 }
1272
1273 if (call->reply_size != call->reply_max) {
1274 _leave(" = -EBADMSG [%u != %u]",
1275 call->reply_size, call->reply_max);
1276 return -EBADMSG;
1277 }
1278
1279 /* unmarshall the reply once we've received all of it */
1280 store_version = NULL;
1281 if (call->operation_ID == FSSTOREDATA)
1282 store_version = &call->store_version;
1283
1284 bp = call->buffer;
1285 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
1286 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1287
1288 _leave(" = 0 [done]");
1289 return 0;
1290}
1291
1292/*
1293 * FS.StoreStatus operation type
1294 */
1295static const struct afs_call_type afs_RXFSStoreStatus = {
1296 .name = "FS.StoreStatus",
1297 .deliver = afs_deliver_fs_store_status,
1298 .abort_to_error = afs_abort_to_error,
1299 .destructor = afs_flat_call_destructor,
1300};
1301
1302static const struct afs_call_type afs_RXFSStoreData_as_Status = {
1303 .name = "FS.StoreData",
1304 .deliver = afs_deliver_fs_store_status,
1305 .abort_to_error = afs_abort_to_error,
1306 .destructor = afs_flat_call_destructor,
1307};
1308
David Howellsb9b1f8d2007-05-10 03:15:21 -07001309static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1310 .name = "FS.StoreData64",
1311 .deliver = afs_deliver_fs_store_status,
1312 .abort_to_error = afs_abort_to_error,
1313 .destructor = afs_flat_call_destructor,
1314};
1315
1316/*
1317 * set the attributes on a very large file, using FS.StoreData rather than
1318 * FS.StoreStatus so as to alter the file size also
1319 */
1320static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
1321 struct afs_vnode *vnode, struct iattr *attr,
1322 const struct afs_wait_mode *wait_mode)
1323{
1324 struct afs_call *call;
1325 __be32 *bp;
1326
1327 _enter(",%x,{%x:%u},,",
1328 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1329
1330 ASSERT(attr->ia_valid & ATTR_SIZE);
1331
1332 call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
1333 (4 + 6 + 3 * 2) * 4,
1334 (21 + 6) * 4);
1335 if (!call)
1336 return -ENOMEM;
1337
1338 call->key = key;
1339 call->reply = vnode;
1340 call->service_id = FS_SERVICE;
1341 call->port = htons(AFS_FS_PORT);
1342 call->store_version = vnode->status.data_version + 1;
1343 call->operation_ID = FSSTOREDATA;
1344
1345 /* marshall the parameters */
1346 bp = call->request;
1347 *bp++ = htonl(FSSTOREDATA64);
1348 *bp++ = htonl(vnode->fid.vid);
1349 *bp++ = htonl(vnode->fid.vnode);
1350 *bp++ = htonl(vnode->fid.unique);
1351
1352 xdr_encode_AFS_StoreStatus(&bp, attr);
1353
1354 *bp++ = 0; /* position of start of write */
1355 *bp++ = 0;
1356 *bp++ = 0; /* size of write */
1357 *bp++ = 0;
1358 *bp++ = htonl(attr->ia_size >> 32); /* new file length */
1359 *bp++ = htonl((u32) attr->ia_size);
1360
1361 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1362}
1363
David Howells31143d52007-05-09 02:33:46 -07001364/*
1365 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
1366 * so as to alter the file size also
1367 */
1368static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
1369 struct afs_vnode *vnode, struct iattr *attr,
1370 const struct afs_wait_mode *wait_mode)
1371{
1372 struct afs_call *call;
1373 __be32 *bp;
1374
1375 _enter(",%x,{%x:%u},,",
1376 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1377
1378 ASSERT(attr->ia_valid & ATTR_SIZE);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001379 if (attr->ia_size >> 32)
1380 return afs_fs_setattr_size64(server, key, vnode, attr,
1381 wait_mode);
David Howells31143d52007-05-09 02:33:46 -07001382
1383 call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
1384 (4 + 6 + 3) * 4,
1385 (21 + 6) * 4);
1386 if (!call)
1387 return -ENOMEM;
1388
1389 call->key = key;
1390 call->reply = vnode;
1391 call->service_id = FS_SERVICE;
1392 call->port = htons(AFS_FS_PORT);
1393 call->store_version = vnode->status.data_version + 1;
1394 call->operation_ID = FSSTOREDATA;
1395
1396 /* marshall the parameters */
1397 bp = call->request;
1398 *bp++ = htonl(FSSTOREDATA);
1399 *bp++ = htonl(vnode->fid.vid);
1400 *bp++ = htonl(vnode->fid.vnode);
1401 *bp++ = htonl(vnode->fid.unique);
1402
1403 xdr_encode_AFS_StoreStatus(&bp, attr);
1404
1405 *bp++ = 0; /* position of start of write */
1406 *bp++ = 0; /* size of write */
1407 *bp++ = htonl(attr->ia_size); /* new file length */
1408
1409 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1410}
1411
1412/*
1413 * set the attributes on a file, using FS.StoreData if there's a change in file
1414 * size, and FS.StoreStatus otherwise
1415 */
1416int afs_fs_setattr(struct afs_server *server, struct key *key,
1417 struct afs_vnode *vnode, struct iattr *attr,
1418 const struct afs_wait_mode *wait_mode)
1419{
1420 struct afs_call *call;
1421 __be32 *bp;
1422
1423 if (attr->ia_valid & ATTR_SIZE)
1424 return afs_fs_setattr_size(server, key, vnode, attr,
1425 wait_mode);
1426
1427 _enter(",%x,{%x:%u},,",
1428 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1429
1430 call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
1431 (4 + 6) * 4,
1432 (21 + 6) * 4);
1433 if (!call)
1434 return -ENOMEM;
1435
1436 call->key = key;
1437 call->reply = vnode;
1438 call->service_id = FS_SERVICE;
1439 call->port = htons(AFS_FS_PORT);
1440 call->operation_ID = FSSTORESTATUS;
1441
1442 /* marshall the parameters */
1443 bp = call->request;
1444 *bp++ = htonl(FSSTORESTATUS);
1445 *bp++ = htonl(vnode->fid.vid);
1446 *bp++ = htonl(vnode->fid.vnode);
1447 *bp++ = htonl(vnode->fid.unique);
1448
1449 xdr_encode_AFS_StoreStatus(&bp, attr);
1450
1451 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1452}