blob: 5dff1308b6f0da5475a20701063036a78bf21b90 [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 Howells45222b92007-05-10 22:22:20 -0700205 * decode an AFSFetchVolumeStatus block
206 */
207static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
208 struct afs_volume_status *vs)
209{
210 const __be32 *bp = *_bp;
211
212 vs->vid = ntohl(*bp++);
213 vs->parent_id = ntohl(*bp++);
214 vs->online = ntohl(*bp++);
215 vs->in_service = ntohl(*bp++);
216 vs->blessed = ntohl(*bp++);
217 vs->needs_salvage = ntohl(*bp++);
218 vs->type = ntohl(*bp++);
219 vs->min_quota = ntohl(*bp++);
220 vs->max_quota = ntohl(*bp++);
221 vs->blocks_in_use = ntohl(*bp++);
222 vs->part_blocks_avail = ntohl(*bp++);
223 vs->part_max_blocks = ntohl(*bp++);
224 *_bp = bp;
225}
226
227/*
David Howells08e0e7c2007-04-26 15:55:03 -0700228 * deliver reply data to an FS.FetchStatus
229 */
230static int afs_deliver_fs_fetch_status(struct afs_call *call,
231 struct sk_buff *skb, bool last)
232{
David Howells260a9802007-04-26 15:59:35 -0700233 struct afs_vnode *vnode = call->reply;
David Howells08e0e7c2007-04-26 15:55:03 -0700234 const __be32 *bp;
235
236 _enter(",,%u", last);
237
238 afs_transfer_reply(call, skb);
239 if (!last)
240 return 0;
241
242 if (call->reply_size != call->reply_max)
243 return -EBADMSG;
244
245 /* unmarshall the reply once we've received all of it */
246 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700247 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700248 xdr_decode_AFSCallBack(&bp, vnode);
David Howells08e0e7c2007-04-26 15:55:03 -0700249 if (call->reply2)
250 xdr_decode_AFSVolSync(&bp, call->reply2);
251
252 _leave(" = 0 [done]");
253 return 0;
254}
255
256/*
257 * FS.FetchStatus operation type
258 */
259static const struct afs_call_type afs_RXFSFetchStatus = {
David Howells00d3b7a2007-04-26 15:57:07 -0700260 .name = "FS.FetchStatus",
David Howells08e0e7c2007-04-26 15:55:03 -0700261 .deliver = afs_deliver_fs_fetch_status,
262 .abort_to_error = afs_abort_to_error,
263 .destructor = afs_flat_call_destructor,
264};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266/*
267 * fetch the status information for a file
268 */
David Howells08e0e7c2007-04-26 15:55:03 -0700269int afs_fs_fetch_file_status(struct afs_server *server,
David Howells00d3b7a2007-04-26 15:57:07 -0700270 struct key *key,
David Howells08e0e7c2007-04-26 15:55:03 -0700271 struct afs_vnode *vnode,
272 struct afs_volsync *volsync,
273 const struct afs_wait_mode *wait_mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
David Howells08e0e7c2007-04-26 15:55:03 -0700275 struct afs_call *call;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 __be32 *bp;
277
David Howells416351f2007-05-09 02:33:45 -0700278 _enter(",%x,{%x:%u},,",
David Howells260a9802007-04-26 15:59:35 -0700279 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
David Howells260a9802007-04-26 15:59:35 -0700281 call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700282 if (!call)
283 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
David Howells00d3b7a2007-04-26 15:57:07 -0700285 call->key = key;
David Howells08e0e7c2007-04-26 15:55:03 -0700286 call->reply = vnode;
287 call->reply2 = volsync;
288 call->service_id = FS_SERVICE;
289 call->port = htons(AFS_FS_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700292 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 bp[0] = htonl(FSFETCHSTATUS);
294 bp[1] = htonl(vnode->fid.vid);
295 bp[2] = htonl(vnode->fid.vnode);
296 bp[3] = htonl(vnode->fid.unique);
297
David Howells08e0e7c2007-04-26 15:55:03 -0700298 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
David Howellsec268152007-04-26 15:49:28 -0700299}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301/*
David Howells08e0e7c2007-04-26 15:55:03 -0700302 * deliver reply data to an FS.FetchData
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 */
David Howells08e0e7c2007-04-26 15:55:03 -0700304static int afs_deliver_fs_fetch_data(struct afs_call *call,
305 struct sk_buff *skb, bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
David Howells260a9802007-04-26 15:59:35 -0700307 struct afs_vnode *vnode = call->reply;
David Howells08e0e7c2007-04-26 15:55:03 -0700308 const __be32 *bp;
309 struct page *page;
310 void *buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 int ret;
David Howells08e0e7c2007-04-26 15:55:03 -0700312
313 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
314
315 switch (call->unmarshall) {
316 case 0:
317 call->offset = 0;
318 call->unmarshall++;
David Howellsb9b1f8d2007-05-10 03:15:21 -0700319 if (call->operation_ID != FSFETCHDATA64) {
320 call->unmarshall++;
321 goto no_msw;
322 }
David Howells08e0e7c2007-04-26 15:55:03 -0700323
David Howellsb9b1f8d2007-05-10 03:15:21 -0700324 /* extract the upper part of the returned data length of an
325 * FSFETCHDATA64 op (which should always be 0 using this
326 * client) */
David Howells08e0e7c2007-04-26 15:55:03 -0700327 case 1:
David Howellsb9b1f8d2007-05-10 03:15:21 -0700328 _debug("extract data length (MSW)");
329 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
330 switch (ret) {
331 case 0: break;
332 case -EAGAIN: return 0;
333 default: return ret;
334 }
335
336 call->count = ntohl(call->tmp);
337 _debug("DATA length MSW: %u", call->count);
338 if (call->count > 0)
339 return -EBADMSG;
340 call->offset = 0;
341 call->unmarshall++;
342
343 no_msw:
344 /* extract the returned data length */
345 case 2:
David Howells08e0e7c2007-04-26 15:55:03 -0700346 _debug("extract data length");
347 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
348 switch (ret) {
349 case 0: break;
350 case -EAGAIN: return 0;
351 default: return ret;
352 }
353
354 call->count = ntohl(call->tmp);
355 _debug("DATA length: %u", call->count);
356 if (call->count > PAGE_SIZE)
357 return -EBADMSG;
358 call->offset = 0;
359 call->unmarshall++;
360
David Howells08e0e7c2007-04-26 15:55:03 -0700361 /* extract the returned data */
David Howellsb9b1f8d2007-05-10 03:15:21 -0700362 case 3:
David Howells08e0e7c2007-04-26 15:55:03 -0700363 _debug("extract data");
David Howells416351f2007-05-09 02:33:45 -0700364 if (call->count > 0) {
365 page = call->reply3;
366 buffer = kmap_atomic(page, KM_USER0);
367 ret = afs_extract_data(call, skb, last, buffer,
368 call->count);
369 kunmap_atomic(buffer, KM_USER0);
370 switch (ret) {
371 case 0: break;
372 case -EAGAIN: return 0;
373 default: return ret;
374 }
David Howells08e0e7c2007-04-26 15:55:03 -0700375 }
376
377 call->offset = 0;
378 call->unmarshall++;
379
380 /* extract the metadata */
David Howellsb9b1f8d2007-05-10 03:15:21 -0700381 case 4:
David Howells260a9802007-04-26 15:59:35 -0700382 ret = afs_extract_data(call, skb, last, call->buffer,
383 (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700384 switch (ret) {
385 case 0: break;
386 case -EAGAIN: return 0;
387 default: return ret;
388 }
389
390 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700391 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700392 xdr_decode_AFSCallBack(&bp, vnode);
David Howells08e0e7c2007-04-26 15:55:03 -0700393 if (call->reply2)
394 xdr_decode_AFSVolSync(&bp, call->reply2);
395
396 call->offset = 0;
397 call->unmarshall++;
398
David Howellsb9b1f8d2007-05-10 03:15:21 -0700399 case 5:
David Howells08e0e7c2007-04-26 15:55:03 -0700400 _debug("trailer");
401 if (skb->len != 0)
402 return -EBADMSG;
403 break;
404 }
405
406 if (!last)
407 return 0;
408
David Howells416351f2007-05-09 02:33:45 -0700409 if (call->count < PAGE_SIZE) {
410 _debug("clear");
411 page = call->reply3;
412 buffer = kmap_atomic(page, KM_USER0);
413 memset(buffer + call->count, 0, PAGE_SIZE - call->count);
414 kunmap_atomic(buffer, KM_USER0);
415 }
416
David Howells08e0e7c2007-04-26 15:55:03 -0700417 _leave(" = 0 [done]");
418 return 0;
419}
420
421/*
422 * FS.FetchData operation type
423 */
424static const struct afs_call_type afs_RXFSFetchData = {
David Howells00d3b7a2007-04-26 15:57:07 -0700425 .name = "FS.FetchData",
David Howells08e0e7c2007-04-26 15:55:03 -0700426 .deliver = afs_deliver_fs_fetch_data,
427 .abort_to_error = afs_abort_to_error,
428 .destructor = afs_flat_call_destructor,
429};
430
David Howellsb9b1f8d2007-05-10 03:15:21 -0700431static const struct afs_call_type afs_RXFSFetchData64 = {
432 .name = "FS.FetchData64",
433 .deliver = afs_deliver_fs_fetch_data,
434 .abort_to_error = afs_abort_to_error,
435 .destructor = afs_flat_call_destructor,
436};
437
438/*
439 * fetch data from a very large file
440 */
441static int afs_fs_fetch_data64(struct afs_server *server,
442 struct key *key,
443 struct afs_vnode *vnode,
444 off_t offset, size_t length,
445 struct page *buffer,
446 const struct afs_wait_mode *wait_mode)
447{
448 struct afs_call *call;
449 __be32 *bp;
450
451 _enter("");
452
453 ASSERTCMP(length, <, ULONG_MAX);
454
455 call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
456 if (!call)
457 return -ENOMEM;
458
459 call->key = key;
460 call->reply = vnode;
461 call->reply2 = NULL; /* volsync */
462 call->reply3 = buffer;
463 call->service_id = FS_SERVICE;
464 call->port = htons(AFS_FS_PORT);
465 call->operation_ID = FSFETCHDATA64;
466
467 /* marshall the parameters */
468 bp = call->request;
469 bp[0] = htonl(FSFETCHDATA64);
470 bp[1] = htonl(vnode->fid.vid);
471 bp[2] = htonl(vnode->fid.vnode);
472 bp[3] = htonl(vnode->fid.unique);
473 bp[4] = htonl(upper_32_bits(offset));
474 bp[5] = htonl((u32) offset);
475 bp[6] = 0;
476 bp[7] = htonl((u32) length);
477
478 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
479}
480
David Howells08e0e7c2007-04-26 15:55:03 -0700481/*
482 * fetch data from a file
483 */
484int afs_fs_fetch_data(struct afs_server *server,
David Howells00d3b7a2007-04-26 15:57:07 -0700485 struct key *key,
David Howells08e0e7c2007-04-26 15:55:03 -0700486 struct afs_vnode *vnode,
487 off_t offset, size_t length,
488 struct page *buffer,
David Howells08e0e7c2007-04-26 15:55:03 -0700489 const struct afs_wait_mode *wait_mode)
490{
491 struct afs_call *call;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 __be32 *bp;
493
David Howellsb9b1f8d2007-05-10 03:15:21 -0700494 if (upper_32_bits(offset) || upper_32_bits(offset + length))
495 return afs_fs_fetch_data64(server, key, vnode, offset, length,
496 buffer, wait_mode);
497
David Howells08e0e7c2007-04-26 15:55:03 -0700498 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
David Howells260a9802007-04-26 15:59:35 -0700500 call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
David Howells08e0e7c2007-04-26 15:55:03 -0700501 if (!call)
502 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
David Howells00d3b7a2007-04-26 15:57:07 -0700504 call->key = key;
David Howells08e0e7c2007-04-26 15:55:03 -0700505 call->reply = vnode;
David Howells260a9802007-04-26 15:59:35 -0700506 call->reply2 = NULL; /* volsync */
David Howells08e0e7c2007-04-26 15:55:03 -0700507 call->reply3 = buffer;
508 call->service_id = FS_SERVICE;
509 call->port = htons(AFS_FS_PORT);
David Howellsb9b1f8d2007-05-10 03:15:21 -0700510 call->operation_ID = FSFETCHDATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700513 bp = call->request;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 bp[0] = htonl(FSFETCHDATA);
David Howells08e0e7c2007-04-26 15:55:03 -0700515 bp[1] = htonl(vnode->fid.vid);
516 bp[2] = htonl(vnode->fid.vnode);
517 bp[3] = htonl(vnode->fid.unique);
518 bp[4] = htonl(offset);
519 bp[5] = htonl(length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
David Howells08e0e7c2007-04-26 15:55:03 -0700521 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
David Howellsec268152007-04-26 15:49:28 -0700522}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524/*
David Howells08e0e7c2007-04-26 15:55:03 -0700525 * deliver reply data to an FS.GiveUpCallBacks
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 */
David Howells08e0e7c2007-04-26 15:55:03 -0700527static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
528 struct sk_buff *skb, bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529{
David Howells08e0e7c2007-04-26 15:55:03 -0700530 _enter(",{%u},%d", skb->len, last);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
David Howells08e0e7c2007-04-26 15:55:03 -0700532 if (skb->len > 0)
533 return -EBADMSG; /* shouldn't be any reply data */
534 return 0;
535}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
David Howells08e0e7c2007-04-26 15:55:03 -0700537/*
538 * FS.GiveUpCallBacks operation type
539 */
540static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
David Howells00d3b7a2007-04-26 15:57:07 -0700541 .name = "FS.GiveUpCallBacks",
David Howells08e0e7c2007-04-26 15:55:03 -0700542 .deliver = afs_deliver_fs_give_up_callbacks,
543 .abort_to_error = afs_abort_to_error,
544 .destructor = afs_flat_call_destructor,
545};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
David Howells08e0e7c2007-04-26 15:55:03 -0700547/*
548 * give up a set of callbacks
549 * - the callbacks are held in the server->cb_break ring
550 */
551int afs_fs_give_up_callbacks(struct afs_server *server,
552 const struct afs_wait_mode *wait_mode)
553{
554 struct afs_call *call;
555 size_t ncallbacks;
556 __be32 *bp, *tp;
557 int loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
David Howells08e0e7c2007-04-26 15:55:03 -0700559 ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
560 ARRAY_SIZE(server->cb_break));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
David Howells08e0e7c2007-04-26 15:55:03 -0700562 _enter("{%zu},", ncallbacks);
563
564 if (ncallbacks == 0)
565 return 0;
566 if (ncallbacks > AFSCBMAX)
567 ncallbacks = AFSCBMAX;
568
569 _debug("break %zu callbacks", ncallbacks);
570
571 call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
572 12 + ncallbacks * 6 * 4, 0);
573 if (!call)
574 return -ENOMEM;
575
576 call->service_id = FS_SERVICE;
577 call->port = htons(AFS_FS_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
579 /* marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700580 bp = call->request;
581 tp = bp + 2 + ncallbacks * 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 *bp++ = htonl(FSGIVEUPCALLBACKS);
David Howells08e0e7c2007-04-26 15:55:03 -0700583 *bp++ = htonl(ncallbacks);
584 *tp++ = htonl(ncallbacks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
David Howells08e0e7c2007-04-26 15:55:03 -0700586 atomic_sub(ncallbacks, &server->cb_break_n);
587 for (loop = ncallbacks; loop > 0; loop--) {
588 struct afs_callback *cb =
589 &server->cb_break[server->cb_break_tail];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
David Howells08e0e7c2007-04-26 15:55:03 -0700591 *bp++ = htonl(cb->fid.vid);
592 *bp++ = htonl(cb->fid.vnode);
593 *bp++ = htonl(cb->fid.unique);
594 *tp++ = htonl(cb->version);
595 *tp++ = htonl(cb->expiry);
596 *tp++ = htonl(cb->type);
597 smp_mb();
598 server->cb_break_tail =
599 (server->cb_break_tail + 1) &
600 (ARRAY_SIZE(server->cb_break) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 }
602
David Howells08e0e7c2007-04-26 15:55:03 -0700603 ASSERT(ncallbacks > 0);
604 wake_up_nr(&server->cb_break_waitq, ncallbacks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
David Howells08e0e7c2007-04-26 15:55:03 -0700606 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
David Howellsec268152007-04-26 15:49:28 -0700607}
David Howells260a9802007-04-26 15:59:35 -0700608
609/*
610 * deliver reply data to an FS.CreateFile or an FS.MakeDir
611 */
612static int afs_deliver_fs_create_vnode(struct afs_call *call,
613 struct sk_buff *skb, bool last)
614{
615 struct afs_vnode *vnode = call->reply;
616 const __be32 *bp;
617
618 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
619
620 afs_transfer_reply(call, skb);
621 if (!last)
622 return 0;
623
624 if (call->reply_size != call->reply_max)
625 return -EBADMSG;
626
627 /* unmarshall the reply once we've received all of it */
628 bp = call->buffer;
629 xdr_decode_AFSFid(&bp, call->reply2);
David Howells31143d52007-05-09 02:33:46 -0700630 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
631 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700632 xdr_decode_AFSCallBack_raw(&bp, call->reply4);
633 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
634
635 _leave(" = 0 [done]");
636 return 0;
637}
638
639/*
640 * FS.CreateFile and FS.MakeDir operation type
641 */
642static const struct afs_call_type afs_RXFSCreateXXXX = {
643 .name = "FS.CreateXXXX",
644 .deliver = afs_deliver_fs_create_vnode,
645 .abort_to_error = afs_abort_to_error,
646 .destructor = afs_flat_call_destructor,
647};
648
649/*
650 * create a file or make a directory
651 */
652int afs_fs_create(struct afs_server *server,
653 struct key *key,
654 struct afs_vnode *vnode,
655 const char *name,
656 umode_t mode,
657 struct afs_fid *newfid,
658 struct afs_file_status *newstatus,
659 struct afs_callback *newcb,
660 const struct afs_wait_mode *wait_mode)
661{
662 struct afs_call *call;
663 size_t namesz, reqsz, padsz;
664 __be32 *bp;
665
666 _enter("");
667
668 namesz = strlen(name);
669 padsz = (4 - (namesz & 3)) & 3;
670 reqsz = (5 * 4) + namesz + padsz + (6 * 4);
671
672 call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
673 (3 + 21 + 21 + 3 + 6) * 4);
674 if (!call)
675 return -ENOMEM;
676
677 call->key = key;
678 call->reply = vnode;
679 call->reply2 = newfid;
680 call->reply3 = newstatus;
681 call->reply4 = newcb;
682 call->service_id = FS_SERVICE;
683 call->port = htons(AFS_FS_PORT);
684
685 /* marshall the parameters */
686 bp = call->request;
687 *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
688 *bp++ = htonl(vnode->fid.vid);
689 *bp++ = htonl(vnode->fid.vnode);
690 *bp++ = htonl(vnode->fid.unique);
691 *bp++ = htonl(namesz);
692 memcpy(bp, name, namesz);
693 bp = (void *) bp + namesz;
694 if (padsz > 0) {
695 memset(bp, 0, padsz);
696 bp = (void *) bp + padsz;
697 }
698 *bp++ = htonl(AFS_SET_MODE);
699 *bp++ = 0; /* mtime */
700 *bp++ = 0; /* owner */
701 *bp++ = 0; /* group */
702 *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
703 *bp++ = 0; /* segment size */
704
705 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
706}
707
708/*
709 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
710 */
711static int afs_deliver_fs_remove(struct afs_call *call,
712 struct sk_buff *skb, bool last)
713{
714 struct afs_vnode *vnode = call->reply;
715 const __be32 *bp;
716
717 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
718
719 afs_transfer_reply(call, skb);
720 if (!last)
721 return 0;
722
723 if (call->reply_size != call->reply_max)
724 return -EBADMSG;
725
726 /* unmarshall the reply once we've received all of it */
727 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700728 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700729 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
730
731 _leave(" = 0 [done]");
732 return 0;
733}
734
735/*
736 * FS.RemoveDir/FS.RemoveFile operation type
737 */
738static const struct afs_call_type afs_RXFSRemoveXXXX = {
739 .name = "FS.RemoveXXXX",
740 .deliver = afs_deliver_fs_remove,
741 .abort_to_error = afs_abort_to_error,
742 .destructor = afs_flat_call_destructor,
743};
744
745/*
746 * remove a file or directory
747 */
748int afs_fs_remove(struct afs_server *server,
749 struct key *key,
750 struct afs_vnode *vnode,
751 const char *name,
752 bool isdir,
753 const struct afs_wait_mode *wait_mode)
754{
755 struct afs_call *call;
756 size_t namesz, reqsz, padsz;
757 __be32 *bp;
758
759 _enter("");
760
761 namesz = strlen(name);
762 padsz = (4 - (namesz & 3)) & 3;
763 reqsz = (5 * 4) + namesz + padsz;
764
765 call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
766 if (!call)
767 return -ENOMEM;
768
769 call->key = key;
770 call->reply = vnode;
771 call->service_id = FS_SERVICE;
772 call->port = htons(AFS_FS_PORT);
773
774 /* marshall the parameters */
775 bp = call->request;
776 *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
777 *bp++ = htonl(vnode->fid.vid);
778 *bp++ = htonl(vnode->fid.vnode);
779 *bp++ = htonl(vnode->fid.unique);
780 *bp++ = htonl(namesz);
781 memcpy(bp, name, namesz);
782 bp = (void *) bp + namesz;
783 if (padsz > 0) {
784 memset(bp, 0, padsz);
785 bp = (void *) bp + padsz;
786 }
787
788 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
789}
790
791/*
792 * deliver reply data to an FS.Link
793 */
794static int afs_deliver_fs_link(struct afs_call *call,
795 struct sk_buff *skb, bool last)
796{
797 struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
798 const __be32 *bp;
799
800 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
801
802 afs_transfer_reply(call, skb);
803 if (!last)
804 return 0;
805
806 if (call->reply_size != call->reply_max)
807 return -EBADMSG;
808
809 /* unmarshall the reply once we've received all of it */
810 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -0700811 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
812 xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700813 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
814
815 _leave(" = 0 [done]");
816 return 0;
817}
818
819/*
820 * FS.Link operation type
821 */
822static const struct afs_call_type afs_RXFSLink = {
823 .name = "FS.Link",
824 .deliver = afs_deliver_fs_link,
825 .abort_to_error = afs_abort_to_error,
826 .destructor = afs_flat_call_destructor,
827};
828
829/*
830 * make a hard link
831 */
832int afs_fs_link(struct afs_server *server,
833 struct key *key,
834 struct afs_vnode *dvnode,
835 struct afs_vnode *vnode,
836 const char *name,
837 const struct afs_wait_mode *wait_mode)
838{
839 struct afs_call *call;
840 size_t namesz, reqsz, padsz;
841 __be32 *bp;
842
843 _enter("");
844
845 namesz = strlen(name);
846 padsz = (4 - (namesz & 3)) & 3;
847 reqsz = (5 * 4) + namesz + padsz + (3 * 4);
848
849 call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
850 if (!call)
851 return -ENOMEM;
852
853 call->key = key;
854 call->reply = dvnode;
855 call->reply2 = vnode;
856 call->service_id = FS_SERVICE;
857 call->port = htons(AFS_FS_PORT);
858
859 /* marshall the parameters */
860 bp = call->request;
861 *bp++ = htonl(FSLINK);
862 *bp++ = htonl(dvnode->fid.vid);
863 *bp++ = htonl(dvnode->fid.vnode);
864 *bp++ = htonl(dvnode->fid.unique);
865 *bp++ = htonl(namesz);
866 memcpy(bp, name, namesz);
867 bp = (void *) bp + namesz;
868 if (padsz > 0) {
869 memset(bp, 0, padsz);
870 bp = (void *) bp + padsz;
871 }
872 *bp++ = htonl(vnode->fid.vid);
873 *bp++ = htonl(vnode->fid.vnode);
874 *bp++ = htonl(vnode->fid.unique);
875
876 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
877}
878
879/*
880 * deliver reply data to an FS.Symlink
881 */
882static int afs_deliver_fs_symlink(struct afs_call *call,
883 struct sk_buff *skb, bool last)
884{
885 struct afs_vnode *vnode = call->reply;
886 const __be32 *bp;
887
888 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
889
890 afs_transfer_reply(call, skb);
891 if (!last)
892 return 0;
893
894 if (call->reply_size != call->reply_max)
895 return -EBADMSG;
896
897 /* unmarshall the reply once we've received all of it */
898 bp = call->buffer;
899 xdr_decode_AFSFid(&bp, call->reply2);
David Howells31143d52007-05-09 02:33:46 -0700900 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
901 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
David Howells260a9802007-04-26 15:59:35 -0700902 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
903
904 _leave(" = 0 [done]");
905 return 0;
906}
907
908/*
909 * FS.Symlink operation type
910 */
911static const struct afs_call_type afs_RXFSSymlink = {
912 .name = "FS.Symlink",
913 .deliver = afs_deliver_fs_symlink,
914 .abort_to_error = afs_abort_to_error,
915 .destructor = afs_flat_call_destructor,
916};
917
918/*
919 * create a symbolic link
920 */
921int afs_fs_symlink(struct afs_server *server,
922 struct key *key,
923 struct afs_vnode *vnode,
924 const char *name,
925 const char *contents,
926 struct afs_fid *newfid,
927 struct afs_file_status *newstatus,
928 const struct afs_wait_mode *wait_mode)
929{
930 struct afs_call *call;
931 size_t namesz, reqsz, padsz, c_namesz, c_padsz;
932 __be32 *bp;
933
934 _enter("");
935
936 namesz = strlen(name);
937 padsz = (4 - (namesz & 3)) & 3;
938
939 c_namesz = strlen(contents);
940 c_padsz = (4 - (c_namesz & 3)) & 3;
941
942 reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
943
944 call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
945 (3 + 21 + 21 + 6) * 4);
946 if (!call)
947 return -ENOMEM;
948
949 call->key = key;
950 call->reply = vnode;
951 call->reply2 = newfid;
952 call->reply3 = newstatus;
953 call->service_id = FS_SERVICE;
954 call->port = htons(AFS_FS_PORT);
955
956 /* marshall the parameters */
957 bp = call->request;
958 *bp++ = htonl(FSSYMLINK);
959 *bp++ = htonl(vnode->fid.vid);
960 *bp++ = htonl(vnode->fid.vnode);
961 *bp++ = htonl(vnode->fid.unique);
962 *bp++ = htonl(namesz);
963 memcpy(bp, name, namesz);
964 bp = (void *) bp + namesz;
965 if (padsz > 0) {
966 memset(bp, 0, padsz);
967 bp = (void *) bp + padsz;
968 }
969 *bp++ = htonl(c_namesz);
970 memcpy(bp, contents, c_namesz);
971 bp = (void *) bp + c_namesz;
972 if (c_padsz > 0) {
973 memset(bp, 0, c_padsz);
974 bp = (void *) bp + c_padsz;
975 }
976 *bp++ = htonl(AFS_SET_MODE);
977 *bp++ = 0; /* mtime */
978 *bp++ = 0; /* owner */
979 *bp++ = 0; /* group */
980 *bp++ = htonl(S_IRWXUGO); /* unix mode */
981 *bp++ = 0; /* segment size */
982
983 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
984}
985
986/*
987 * deliver reply data to an FS.Rename
988 */
989static int afs_deliver_fs_rename(struct afs_call *call,
990 struct sk_buff *skb, bool last)
991{
992 struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
993 const __be32 *bp;
994
995 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
996
997 afs_transfer_reply(call, skb);
998 if (!last)
999 return 0;
1000
1001 if (call->reply_size != call->reply_max)
1002 return -EBADMSG;
1003
1004 /* unmarshall the reply once we've received all of it */
1005 bp = call->buffer;
David Howells31143d52007-05-09 02:33:46 -07001006 xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
David Howells260a9802007-04-26 15:59:35 -07001007 if (new_dvnode != orig_dvnode)
David Howells31143d52007-05-09 02:33:46 -07001008 xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
1009 NULL);
David Howells260a9802007-04-26 15:59:35 -07001010 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1011
1012 _leave(" = 0 [done]");
1013 return 0;
1014}
1015
1016/*
1017 * FS.Rename operation type
1018 */
1019static const struct afs_call_type afs_RXFSRename = {
1020 .name = "FS.Rename",
1021 .deliver = afs_deliver_fs_rename,
1022 .abort_to_error = afs_abort_to_error,
1023 .destructor = afs_flat_call_destructor,
1024};
1025
1026/*
1027 * create a symbolic link
1028 */
1029int afs_fs_rename(struct afs_server *server,
1030 struct key *key,
1031 struct afs_vnode *orig_dvnode,
1032 const char *orig_name,
1033 struct afs_vnode *new_dvnode,
1034 const char *new_name,
1035 const struct afs_wait_mode *wait_mode)
1036{
1037 struct afs_call *call;
1038 size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1039 __be32 *bp;
1040
1041 _enter("");
1042
1043 o_namesz = strlen(orig_name);
1044 o_padsz = (4 - (o_namesz & 3)) & 3;
1045
1046 n_namesz = strlen(new_name);
1047 n_padsz = (4 - (n_namesz & 3)) & 3;
1048
1049 reqsz = (4 * 4) +
1050 4 + o_namesz + o_padsz +
1051 (3 * 4) +
1052 4 + n_namesz + n_padsz;
1053
1054 call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1055 if (!call)
1056 return -ENOMEM;
1057
1058 call->key = key;
1059 call->reply = orig_dvnode;
1060 call->reply2 = new_dvnode;
1061 call->service_id = FS_SERVICE;
1062 call->port = htons(AFS_FS_PORT);
1063
1064 /* marshall the parameters */
1065 bp = call->request;
1066 *bp++ = htonl(FSRENAME);
1067 *bp++ = htonl(orig_dvnode->fid.vid);
1068 *bp++ = htonl(orig_dvnode->fid.vnode);
1069 *bp++ = htonl(orig_dvnode->fid.unique);
1070 *bp++ = htonl(o_namesz);
1071 memcpy(bp, orig_name, o_namesz);
1072 bp = (void *) bp + o_namesz;
1073 if (o_padsz > 0) {
1074 memset(bp, 0, o_padsz);
1075 bp = (void *) bp + o_padsz;
1076 }
1077
1078 *bp++ = htonl(new_dvnode->fid.vid);
1079 *bp++ = htonl(new_dvnode->fid.vnode);
1080 *bp++ = htonl(new_dvnode->fid.unique);
1081 *bp++ = htonl(n_namesz);
1082 memcpy(bp, new_name, n_namesz);
1083 bp = (void *) bp + n_namesz;
1084 if (n_padsz > 0) {
1085 memset(bp, 0, n_padsz);
1086 bp = (void *) bp + n_padsz;
1087 }
1088
1089 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1090}
David Howells31143d52007-05-09 02:33:46 -07001091
1092/*
1093 * deliver reply data to an FS.StoreData
1094 */
1095static int afs_deliver_fs_store_data(struct afs_call *call,
1096 struct sk_buff *skb, bool last)
1097{
1098 struct afs_vnode *vnode = call->reply;
1099 const __be32 *bp;
1100
1101 _enter(",,%u", last);
1102
1103 afs_transfer_reply(call, skb);
1104 if (!last) {
1105 _leave(" = 0 [more]");
1106 return 0;
1107 }
1108
1109 if (call->reply_size != call->reply_max) {
1110 _leave(" = -EBADMSG [%u != %u]",
1111 call->reply_size, call->reply_max);
1112 return -EBADMSG;
1113 }
1114
1115 /* unmarshall the reply once we've received all of it */
1116 bp = call->buffer;
1117 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
1118 &call->store_version);
1119 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1120
1121 afs_pages_written_back(vnode, call);
1122
1123 _leave(" = 0 [done]");
1124 return 0;
1125}
1126
1127/*
1128 * FS.StoreData operation type
1129 */
1130static const struct afs_call_type afs_RXFSStoreData = {
1131 .name = "FS.StoreData",
1132 .deliver = afs_deliver_fs_store_data,
1133 .abort_to_error = afs_abort_to_error,
1134 .destructor = afs_flat_call_destructor,
1135};
1136
David Howellsb9b1f8d2007-05-10 03:15:21 -07001137static const struct afs_call_type afs_RXFSStoreData64 = {
1138 .name = "FS.StoreData64",
1139 .deliver = afs_deliver_fs_store_data,
1140 .abort_to_error = afs_abort_to_error,
1141 .destructor = afs_flat_call_destructor,
1142};
1143
1144/*
1145 * store a set of pages to a very large file
1146 */
1147static int afs_fs_store_data64(struct afs_server *server,
1148 struct afs_writeback *wb,
1149 pgoff_t first, pgoff_t last,
1150 unsigned offset, unsigned to,
1151 loff_t size, loff_t pos, loff_t i_size,
1152 const struct afs_wait_mode *wait_mode)
1153{
1154 struct afs_vnode *vnode = wb->vnode;
1155 struct afs_call *call;
1156 __be32 *bp;
1157
1158 _enter(",%x,{%x:%u},,",
1159 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1160
1161 call = afs_alloc_flat_call(&afs_RXFSStoreData64,
1162 (4 + 6 + 3 * 2) * 4,
1163 (21 + 6) * 4);
1164 if (!call)
1165 return -ENOMEM;
1166
1167 call->wb = wb;
1168 call->key = wb->key;
1169 call->reply = vnode;
1170 call->service_id = FS_SERVICE;
1171 call->port = htons(AFS_FS_PORT);
1172 call->mapping = vnode->vfs_inode.i_mapping;
1173 call->first = first;
1174 call->last = last;
1175 call->first_offset = offset;
1176 call->last_to = to;
1177 call->send_pages = true;
1178 call->store_version = vnode->status.data_version + 1;
1179
1180 /* marshall the parameters */
1181 bp = call->request;
1182 *bp++ = htonl(FSSTOREDATA64);
1183 *bp++ = htonl(vnode->fid.vid);
1184 *bp++ = htonl(vnode->fid.vnode);
1185 *bp++ = htonl(vnode->fid.unique);
1186
1187 *bp++ = 0; /* mask */
1188 *bp++ = 0; /* mtime */
1189 *bp++ = 0; /* owner */
1190 *bp++ = 0; /* group */
1191 *bp++ = 0; /* unix mode */
1192 *bp++ = 0; /* segment size */
1193
1194 *bp++ = htonl(pos >> 32);
1195 *bp++ = htonl((u32) pos);
1196 *bp++ = htonl(size >> 32);
1197 *bp++ = htonl((u32) size);
1198 *bp++ = htonl(i_size >> 32);
1199 *bp++ = htonl((u32) i_size);
1200
1201 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1202}
1203
David Howells31143d52007-05-09 02:33:46 -07001204/*
1205 * store a set of pages
1206 */
1207int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
1208 pgoff_t first, pgoff_t last,
1209 unsigned offset, unsigned to,
1210 const struct afs_wait_mode *wait_mode)
1211{
1212 struct afs_vnode *vnode = wb->vnode;
1213 struct afs_call *call;
1214 loff_t size, pos, i_size;
1215 __be32 *bp;
1216
1217 _enter(",%x,{%x:%u},,",
1218 key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1219
1220 size = to - offset;
1221 if (first != last)
1222 size += (loff_t)(last - first) << PAGE_SHIFT;
1223 pos = (loff_t)first << PAGE_SHIFT;
1224 pos += offset;
1225
1226 i_size = i_size_read(&vnode->vfs_inode);
1227 if (pos + size > i_size)
1228 i_size = size + pos;
1229
1230 _debug("size %llx, at %llx, i_size %llx",
1231 (unsigned long long) size, (unsigned long long) pos,
1232 (unsigned long long) i_size);
1233
David Howellsb9b1f8d2007-05-10 03:15:21 -07001234 if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
1235 return afs_fs_store_data64(server, wb, first, last, offset, to,
1236 size, pos, i_size, wait_mode);
David Howells31143d52007-05-09 02:33:46 -07001237
1238 call = afs_alloc_flat_call(&afs_RXFSStoreData,
1239 (4 + 6 + 3) * 4,
1240 (21 + 6) * 4);
1241 if (!call)
1242 return -ENOMEM;
1243
1244 call->wb = wb;
1245 call->key = wb->key;
1246 call->reply = vnode;
1247 call->service_id = FS_SERVICE;
1248 call->port = htons(AFS_FS_PORT);
1249 call->mapping = vnode->vfs_inode.i_mapping;
1250 call->first = first;
1251 call->last = last;
1252 call->first_offset = offset;
1253 call->last_to = to;
1254 call->send_pages = true;
1255 call->store_version = vnode->status.data_version + 1;
1256
1257 /* marshall the parameters */
1258 bp = call->request;
1259 *bp++ = htonl(FSSTOREDATA);
1260 *bp++ = htonl(vnode->fid.vid);
1261 *bp++ = htonl(vnode->fid.vnode);
1262 *bp++ = htonl(vnode->fid.unique);
1263
1264 *bp++ = 0; /* mask */
1265 *bp++ = 0; /* mtime */
1266 *bp++ = 0; /* owner */
1267 *bp++ = 0; /* group */
1268 *bp++ = 0; /* unix mode */
1269 *bp++ = 0; /* segment size */
1270
1271 *bp++ = htonl(pos);
1272 *bp++ = htonl(size);
1273 *bp++ = htonl(i_size);
1274
1275 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1276}
1277
1278/*
1279 * deliver reply data to an FS.StoreStatus
1280 */
1281static int afs_deliver_fs_store_status(struct afs_call *call,
1282 struct sk_buff *skb, bool last)
1283{
1284 afs_dataversion_t *store_version;
1285 struct afs_vnode *vnode = call->reply;
1286 const __be32 *bp;
1287
1288 _enter(",,%u", last);
1289
1290 afs_transfer_reply(call, skb);
1291 if (!last) {
1292 _leave(" = 0 [more]");
1293 return 0;
1294 }
1295
1296 if (call->reply_size != call->reply_max) {
1297 _leave(" = -EBADMSG [%u != %u]",
1298 call->reply_size, call->reply_max);
1299 return -EBADMSG;
1300 }
1301
1302 /* unmarshall the reply once we've received all of it */
1303 store_version = NULL;
1304 if (call->operation_ID == FSSTOREDATA)
1305 store_version = &call->store_version;
1306
1307 bp = call->buffer;
1308 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
1309 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
1310
1311 _leave(" = 0 [done]");
1312 return 0;
1313}
1314
1315/*
1316 * FS.StoreStatus operation type
1317 */
1318static const struct afs_call_type afs_RXFSStoreStatus = {
1319 .name = "FS.StoreStatus",
1320 .deliver = afs_deliver_fs_store_status,
1321 .abort_to_error = afs_abort_to_error,
1322 .destructor = afs_flat_call_destructor,
1323};
1324
1325static const struct afs_call_type afs_RXFSStoreData_as_Status = {
1326 .name = "FS.StoreData",
1327 .deliver = afs_deliver_fs_store_status,
1328 .abort_to_error = afs_abort_to_error,
1329 .destructor = afs_flat_call_destructor,
1330};
1331
David Howellsb9b1f8d2007-05-10 03:15:21 -07001332static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1333 .name = "FS.StoreData64",
1334 .deliver = afs_deliver_fs_store_status,
1335 .abort_to_error = afs_abort_to_error,
1336 .destructor = afs_flat_call_destructor,
1337};
1338
1339/*
1340 * set the attributes on a very large file, using FS.StoreData rather than
1341 * FS.StoreStatus so as to alter the file size also
1342 */
1343static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
1344 struct afs_vnode *vnode, struct iattr *attr,
1345 const struct afs_wait_mode *wait_mode)
1346{
1347 struct afs_call *call;
1348 __be32 *bp;
1349
1350 _enter(",%x,{%x:%u},,",
1351 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1352
1353 ASSERT(attr->ia_valid & ATTR_SIZE);
1354
1355 call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
1356 (4 + 6 + 3 * 2) * 4,
1357 (21 + 6) * 4);
1358 if (!call)
1359 return -ENOMEM;
1360
1361 call->key = key;
1362 call->reply = vnode;
1363 call->service_id = FS_SERVICE;
1364 call->port = htons(AFS_FS_PORT);
1365 call->store_version = vnode->status.data_version + 1;
1366 call->operation_ID = FSSTOREDATA;
1367
1368 /* marshall the parameters */
1369 bp = call->request;
1370 *bp++ = htonl(FSSTOREDATA64);
1371 *bp++ = htonl(vnode->fid.vid);
1372 *bp++ = htonl(vnode->fid.vnode);
1373 *bp++ = htonl(vnode->fid.unique);
1374
1375 xdr_encode_AFS_StoreStatus(&bp, attr);
1376
1377 *bp++ = 0; /* position of start of write */
1378 *bp++ = 0;
1379 *bp++ = 0; /* size of write */
1380 *bp++ = 0;
1381 *bp++ = htonl(attr->ia_size >> 32); /* new file length */
1382 *bp++ = htonl((u32) attr->ia_size);
1383
1384 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1385}
1386
David Howells31143d52007-05-09 02:33:46 -07001387/*
1388 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
1389 * so as to alter the file size also
1390 */
1391static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
1392 struct afs_vnode *vnode, struct iattr *attr,
1393 const struct afs_wait_mode *wait_mode)
1394{
1395 struct afs_call *call;
1396 __be32 *bp;
1397
1398 _enter(",%x,{%x:%u},,",
1399 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1400
1401 ASSERT(attr->ia_valid & ATTR_SIZE);
David Howellsb9b1f8d2007-05-10 03:15:21 -07001402 if (attr->ia_size >> 32)
1403 return afs_fs_setattr_size64(server, key, vnode, attr,
1404 wait_mode);
David Howells31143d52007-05-09 02:33:46 -07001405
1406 call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
1407 (4 + 6 + 3) * 4,
1408 (21 + 6) * 4);
1409 if (!call)
1410 return -ENOMEM;
1411
1412 call->key = key;
1413 call->reply = vnode;
1414 call->service_id = FS_SERVICE;
1415 call->port = htons(AFS_FS_PORT);
1416 call->store_version = vnode->status.data_version + 1;
1417 call->operation_ID = FSSTOREDATA;
1418
1419 /* marshall the parameters */
1420 bp = call->request;
1421 *bp++ = htonl(FSSTOREDATA);
1422 *bp++ = htonl(vnode->fid.vid);
1423 *bp++ = htonl(vnode->fid.vnode);
1424 *bp++ = htonl(vnode->fid.unique);
1425
1426 xdr_encode_AFS_StoreStatus(&bp, attr);
1427
1428 *bp++ = 0; /* position of start of write */
1429 *bp++ = 0; /* size of write */
1430 *bp++ = htonl(attr->ia_size); /* new file length */
1431
1432 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1433}
1434
1435/*
1436 * set the attributes on a file, using FS.StoreData if there's a change in file
1437 * size, and FS.StoreStatus otherwise
1438 */
1439int afs_fs_setattr(struct afs_server *server, struct key *key,
1440 struct afs_vnode *vnode, struct iattr *attr,
1441 const struct afs_wait_mode *wait_mode)
1442{
1443 struct afs_call *call;
1444 __be32 *bp;
1445
1446 if (attr->ia_valid & ATTR_SIZE)
1447 return afs_fs_setattr_size(server, key, vnode, attr,
1448 wait_mode);
1449
1450 _enter(",%x,{%x:%u},,",
1451 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1452
1453 call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
1454 (4 + 6) * 4,
1455 (21 + 6) * 4);
1456 if (!call)
1457 return -ENOMEM;
1458
1459 call->key = key;
1460 call->reply = vnode;
1461 call->service_id = FS_SERVICE;
1462 call->port = htons(AFS_FS_PORT);
1463 call->operation_ID = FSSTORESTATUS;
1464
1465 /* marshall the parameters */
1466 bp = call->request;
1467 *bp++ = htonl(FSSTORESTATUS);
1468 *bp++ = htonl(vnode->fid.vid);
1469 *bp++ = htonl(vnode->fid.vnode);
1470 *bp++ = htonl(vnode->fid.unique);
1471
1472 xdr_encode_AFS_StoreStatus(&bp, attr);
1473
1474 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1475}
David Howells45222b92007-05-10 22:22:20 -07001476
1477/*
1478 * deliver reply data to an FS.GetVolumeStatus
1479 */
1480static int afs_deliver_fs_get_volume_status(struct afs_call *call,
1481 struct sk_buff *skb, bool last)
1482{
1483 const __be32 *bp;
1484 char *p;
1485 int ret;
1486
1487 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
1488
1489 switch (call->unmarshall) {
1490 case 0:
1491 call->offset = 0;
1492 call->unmarshall++;
1493
1494 /* extract the returned status record */
1495 case 1:
1496 _debug("extract status");
1497 ret = afs_extract_data(call, skb, last, call->buffer,
1498 12 * 4);
1499 switch (ret) {
1500 case 0: break;
1501 case -EAGAIN: return 0;
1502 default: return ret;
1503 }
1504
1505 bp = call->buffer;
1506 xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
1507 call->offset = 0;
1508 call->unmarshall++;
1509
1510 /* extract the volume name length */
1511 case 2:
1512 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
1513 switch (ret) {
1514 case 0: break;
1515 case -EAGAIN: return 0;
1516 default: return ret;
1517 }
1518
1519 call->count = ntohl(call->tmp);
1520 _debug("volname length: %u", call->count);
1521 if (call->count >= AFSNAMEMAX)
1522 return -EBADMSG;
1523 call->offset = 0;
1524 call->unmarshall++;
1525
1526 /* extract the volume name */
1527 case 3:
1528 _debug("extract volname");
1529 if (call->count > 0) {
1530 ret = afs_extract_data(call, skb, last, call->reply3,
1531 call->count);
1532 switch (ret) {
1533 case 0: break;
1534 case -EAGAIN: return 0;
1535 default: return ret;
1536 }
1537 }
1538
1539 p = call->reply3;
1540 p[call->count] = 0;
1541 _debug("volname '%s'", p);
1542
1543 call->offset = 0;
1544 call->unmarshall++;
1545
1546 /* extract the volume name padding */
1547 if ((call->count & 3) == 0) {
1548 call->unmarshall++;
1549 goto no_volname_padding;
1550 }
1551 call->count = 4 - (call->count & 3);
1552
1553 case 4:
1554 ret = afs_extract_data(call, skb, last, call->buffer,
1555 call->count);
1556 switch (ret) {
1557 case 0: break;
1558 case -EAGAIN: return 0;
1559 default: return ret;
1560 }
1561
1562 call->offset = 0;
1563 call->unmarshall++;
1564 no_volname_padding:
1565
1566 /* extract the offline message length */
1567 case 5:
1568 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
1569 switch (ret) {
1570 case 0: break;
1571 case -EAGAIN: return 0;
1572 default: return ret;
1573 }
1574
1575 call->count = ntohl(call->tmp);
1576 _debug("offline msg length: %u", call->count);
1577 if (call->count >= AFSNAMEMAX)
1578 return -EBADMSG;
1579 call->offset = 0;
1580 call->unmarshall++;
1581
1582 /* extract the offline message */
1583 case 6:
1584 _debug("extract offline");
1585 if (call->count > 0) {
1586 ret = afs_extract_data(call, skb, last, call->reply3,
1587 call->count);
1588 switch (ret) {
1589 case 0: break;
1590 case -EAGAIN: return 0;
1591 default: return ret;
1592 }
1593 }
1594
1595 p = call->reply3;
1596 p[call->count] = 0;
1597 _debug("offline '%s'", p);
1598
1599 call->offset = 0;
1600 call->unmarshall++;
1601
1602 /* extract the offline message padding */
1603 if ((call->count & 3) == 0) {
1604 call->unmarshall++;
1605 goto no_offline_padding;
1606 }
1607 call->count = 4 - (call->count & 3);
1608
1609 case 7:
1610 ret = afs_extract_data(call, skb, last, call->buffer,
1611 call->count);
1612 switch (ret) {
1613 case 0: break;
1614 case -EAGAIN: return 0;
1615 default: return ret;
1616 }
1617
1618 call->offset = 0;
1619 call->unmarshall++;
1620 no_offline_padding:
1621
1622 /* extract the message of the day length */
1623 case 8:
1624 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
1625 switch (ret) {
1626 case 0: break;
1627 case -EAGAIN: return 0;
1628 default: return ret;
1629 }
1630
1631 call->count = ntohl(call->tmp);
1632 _debug("motd length: %u", call->count);
1633 if (call->count >= AFSNAMEMAX)
1634 return -EBADMSG;
1635 call->offset = 0;
1636 call->unmarshall++;
1637
1638 /* extract the message of the day */
1639 case 9:
1640 _debug("extract motd");
1641 if (call->count > 0) {
1642 ret = afs_extract_data(call, skb, last, call->reply3,
1643 call->count);
1644 switch (ret) {
1645 case 0: break;
1646 case -EAGAIN: return 0;
1647 default: return ret;
1648 }
1649 }
1650
1651 p = call->reply3;
1652 p[call->count] = 0;
1653 _debug("motd '%s'", p);
1654
1655 call->offset = 0;
1656 call->unmarshall++;
1657
1658 /* extract the message of the day padding */
1659 if ((call->count & 3) == 0) {
1660 call->unmarshall++;
1661 goto no_motd_padding;
1662 }
1663 call->count = 4 - (call->count & 3);
1664
1665 case 10:
1666 ret = afs_extract_data(call, skb, last, call->buffer,
1667 call->count);
1668 switch (ret) {
1669 case 0: break;
1670 case -EAGAIN: return 0;
1671 default: return ret;
1672 }
1673
1674 call->offset = 0;
1675 call->unmarshall++;
1676 no_motd_padding:
1677
1678 case 11:
1679 _debug("trailer %d", skb->len);
1680 if (skb->len != 0)
1681 return -EBADMSG;
1682 break;
1683 }
1684
1685 if (!last)
1686 return 0;
1687
1688 _leave(" = 0 [done]");
1689 return 0;
1690}
1691
1692/*
1693 * destroy an FS.GetVolumeStatus call
1694 */
1695static void afs_get_volume_status_call_destructor(struct afs_call *call)
1696{
1697 kfree(call->reply3);
1698 call->reply3 = NULL;
1699 afs_flat_call_destructor(call);
1700}
1701
1702/*
1703 * FS.GetVolumeStatus operation type
1704 */
1705static const struct afs_call_type afs_RXFSGetVolumeStatus = {
1706 .name = "FS.GetVolumeStatus",
1707 .deliver = afs_deliver_fs_get_volume_status,
1708 .abort_to_error = afs_abort_to_error,
1709 .destructor = afs_get_volume_status_call_destructor,
1710};
1711
1712/*
1713 * fetch the status of a volume
1714 */
1715int afs_fs_get_volume_status(struct afs_server *server,
1716 struct key *key,
1717 struct afs_vnode *vnode,
1718 struct afs_volume_status *vs,
1719 const struct afs_wait_mode *wait_mode)
1720{
1721 struct afs_call *call;
1722 __be32 *bp;
1723 void *tmpbuf;
1724
1725 _enter("");
1726
1727 tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
1728 if (!tmpbuf)
1729 return -ENOMEM;
1730
1731 call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
1732 if (!call) {
1733 kfree(tmpbuf);
1734 return -ENOMEM;
1735 }
1736
1737 call->key = key;
1738 call->reply = vnode;
1739 call->reply2 = vs;
1740 call->reply3 = tmpbuf;
1741 call->service_id = FS_SERVICE;
1742 call->port = htons(AFS_FS_PORT);
1743
1744 /* marshall the parameters */
1745 bp = call->request;
1746 bp[0] = htonl(FSGETVOLUMESTATUS);
1747 bp[1] = htonl(vnode->fid.vid);
1748
1749 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1750}