]>
Commit | Line | Data |
---|---|---|
08e0e7c8 | 1 | /* AFS File Server client stubs |
1da177e4 | 2 | * |
08e0e7c8 | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
1da177e4 LT |
4 | * Written by David Howells ([email protected]) |
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> | |
5a0e3ad6 | 13 | #include <linux/slab.h> |
1da177e4 | 14 | #include <linux/sched.h> |
08e0e7c8 | 15 | #include <linux/circ_buf.h> |
a01179e6 | 16 | #include <linux/iversion.h> |
1da177e4 | 17 | #include "internal.h" |
08e0e7c8 | 18 | #include "afs_fs.h" |
dd9fbcb8 | 19 | #include "xdr_fs.h" |
1da177e4 | 20 | |
025db80c DH |
21 | static const struct afs_fid afs_zero_fid; |
22 | ||
6db3ac3c DH |
23 | /* |
24 | * We need somewhere to discard into in case the server helpfully returns more | |
25 | * than we asked for in FS.FetchData{,64}. | |
26 | */ | |
27 | static u8 afs_discard_buffer[64]; | |
28 | ||
d2ddc776 | 29 | static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi) |
c435ee34 | 30 | { |
d2ddc776 | 31 | call->cbi = afs_get_cb_interest(cbi); |
c435ee34 DH |
32 | } |
33 | ||
260a9803 DH |
34 | /* |
35 | * decode an AFSFid block | |
36 | */ | |
37 | static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) | |
38 | { | |
39 | const __be32 *bp = *_bp; | |
40 | ||
41 | fid->vid = ntohl(*bp++); | |
42 | fid->vnode = ntohl(*bp++); | |
43 | fid->unique = ntohl(*bp++); | |
44 | *_bp = bp; | |
45 | } | |
46 | ||
888b3384 DH |
47 | /* |
48 | * Dump a bad file status record. | |
49 | */ | |
50 | static void xdr_dump_bad(const __be32 *bp) | |
51 | { | |
52 | __be32 x[4]; | |
53 | int i; | |
54 | ||
55 | pr_notice("AFS XDR: Bad status record\n"); | |
56 | for (i = 0; i < 5 * 4 * 4; i += 16) { | |
57 | memcpy(x, bp, 16); | |
58 | bp += 4; | |
59 | pr_notice("%03x: %08x %08x %08x %08x\n", | |
60 | i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3])); | |
61 | } | |
62 | ||
63 | memcpy(x, bp, 4); | |
64 | pr_notice("0x50: %08x\n", ntohl(x[0])); | |
65 | } | |
66 | ||
1da177e4 | 67 | /* |
dd9fbcb8 | 68 | * Update the core inode struct from a returned status record. |
1da177e4 | 69 | */ |
dd9fbcb8 DH |
70 | void afs_update_inode_from_status(struct afs_vnode *vnode, |
71 | struct afs_file_status *status, | |
72 | const afs_dataversion_t *expected_version, | |
73 | u8 flags) | |
1da177e4 | 74 | { |
95582b00 | 75 | struct timespec64 t; |
08e0e7c8 | 76 | umode_t mode; |
dd9fbcb8 DH |
77 | |
78 | t.tv_sec = status->mtime_client; | |
79 | t.tv_nsec = 0; | |
80 | vnode->vfs_inode.i_ctime = t; | |
81 | vnode->vfs_inode.i_mtime = t; | |
82 | vnode->vfs_inode.i_atime = t; | |
83 | ||
84 | if (flags & (AFS_VNODE_META_CHANGED | AFS_VNODE_NOT_YET_SET)) { | |
85 | vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner); | |
86 | vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group); | |
87 | set_nlink(&vnode->vfs_inode, status->nlink); | |
88 | ||
89 | mode = vnode->vfs_inode.i_mode; | |
90 | mode &= ~S_IALLUGO; | |
91 | mode |= status->mode; | |
92 | barrier(); | |
93 | vnode->vfs_inode.i_mode = mode; | |
94 | } | |
95 | ||
96 | if (!(flags & AFS_VNODE_NOT_YET_SET)) { | |
97 | if (expected_version && | |
98 | *expected_version != status->data_version) { | |
99 | _debug("vnode modified %llx on {%x:%u} [exp %llx]", | |
100 | (unsigned long long) status->data_version, | |
101 | vnode->fid.vid, vnode->fid.vnode, | |
102 | (unsigned long long) *expected_version); | |
a4ff7401 | 103 | vnode->invalid_before = status->data_version; |
f3ddee8d DH |
104 | if (vnode->status.type == AFS_FTYPE_DIR) { |
105 | if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) | |
106 | afs_stat_v(vnode, n_inval); | |
107 | } else { | |
108 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); | |
109 | } | |
63a4681f DH |
110 | } else if (vnode->status.type == AFS_FTYPE_DIR) { |
111 | /* Expected directory change is handled elsewhere so | |
112 | * that we can locally edit the directory and save on a | |
113 | * download. | |
114 | */ | |
115 | if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) | |
116 | flags &= ~AFS_VNODE_DATA_CHANGED; | |
dd9fbcb8 DH |
117 | } |
118 | } | |
119 | ||
120 | if (flags & (AFS_VNODE_DATA_CHANGED | AFS_VNODE_NOT_YET_SET)) { | |
121 | inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); | |
122 | i_size_write(&vnode->vfs_inode, status->size); | |
123 | } | |
124 | } | |
125 | ||
126 | /* | |
127 | * decode an AFSFetchStatus block | |
128 | */ | |
5f702c8e DH |
129 | static int xdr_decode_AFSFetchStatus(struct afs_call *call, |
130 | const __be32 **_bp, | |
dd9fbcb8 DH |
131 | struct afs_file_status *status, |
132 | struct afs_vnode *vnode, | |
133 | const afs_dataversion_t *expected_version, | |
f3ddee8d | 134 | struct afs_read *read_req) |
dd9fbcb8 DH |
135 | { |
136 | const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; | |
684b0f68 | 137 | bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus); |
260a9803 | 138 | u64 data_version, size; |
dd9fbcb8 DH |
139 | u32 type, abort_code; |
140 | u8 flags = 0; | |
c435ee34 | 141 | |
684b0f68 DH |
142 | abort_code = ntohl(xdr->abort_code); |
143 | ||
dd9fbcb8 | 144 | if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { |
684b0f68 DH |
145 | if (xdr->if_version == htonl(0) && |
146 | abort_code != 0 && | |
147 | inline_error) { | |
148 | /* The OpenAFS fileserver has a bug in FS.InlineBulkStatus | |
149 | * whereby it doesn't set the interface version in the error | |
150 | * case. | |
151 | */ | |
152 | status->abort_code = abort_code; | |
de52cf92 | 153 | return 0; |
684b0f68 DH |
154 | } |
155 | ||
dd9fbcb8 DH |
156 | pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); |
157 | goto bad; | |
158 | } | |
08e0e7c8 | 159 | |
684b0f68 DH |
160 | if (abort_code != 0 && inline_error) { |
161 | status->abort_code = abort_code; | |
de52cf92 | 162 | return 0; |
684b0f68 DH |
163 | } |
164 | ||
dd9fbcb8 | 165 | type = ntohl(xdr->type); |
dd9fbcb8 | 166 | switch (type) { |
888b3384 DH |
167 | case AFS_FTYPE_FILE: |
168 | case AFS_FTYPE_DIR: | |
169 | case AFS_FTYPE_SYMLINK: | |
dd9fbcb8 DH |
170 | if (type != status->type && |
171 | vnode && | |
172 | !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | |
173 | pr_warning("Vnode %x:%x:%x changed type %u to %u\n", | |
174 | vnode->fid.vid, | |
175 | vnode->fid.vnode, | |
176 | vnode->fid.unique, | |
177 | status->type, type); | |
178 | goto bad; | |
179 | } | |
180 | status->type = type; | |
888b3384 | 181 | break; |
888b3384 | 182 | default: |
dd9fbcb8 | 183 | goto bad; |
888b3384 DH |
184 | } |
185 | ||
dd9fbcb8 DH |
186 | #define EXTRACT_M(FIELD) \ |
187 | do { \ | |
188 | u32 x = ntohl(xdr->FIELD); \ | |
189 | if (status->FIELD != x) { \ | |
190 | flags |= AFS_VNODE_META_CHANGED; \ | |
191 | status->FIELD = x; \ | |
192 | } \ | |
193 | } while (0) | |
194 | ||
195 | EXTRACT_M(nlink); | |
196 | EXTRACT_M(author); | |
197 | EXTRACT_M(owner); | |
198 | EXTRACT_M(caller_access); /* call ticket dependent */ | |
199 | EXTRACT_M(anon_access); | |
200 | EXTRACT_M(mode); | |
201 | EXTRACT_M(group); | |
202 | ||
203 | status->mtime_client = ntohl(xdr->mtime_client); | |
204 | status->mtime_server = ntohl(xdr->mtime_server); | |
205 | status->lock_count = ntohl(xdr->lock_count); | |
206 | ||
207 | size = (u64)ntohl(xdr->size_lo); | |
208 | size |= (u64)ntohl(xdr->size_hi) << 32; | |
63a4681f | 209 | status->size = size; |
dd9fbcb8 DH |
210 | |
211 | data_version = (u64)ntohl(xdr->data_version_lo); | |
212 | data_version |= (u64)ntohl(xdr->data_version_hi) << 32; | |
213 | if (data_version != status->data_version) { | |
214 | status->data_version = data_version; | |
215 | flags |= AFS_VNODE_DATA_CHANGED; | |
08e0e7c8 | 216 | } |
f3ddee8d DH |
217 | |
218 | if (read_req) { | |
219 | read_req->data_version = data_version; | |
220 | read_req->file_size = size; | |
221 | } | |
08e0e7c8 | 222 | |
dd9fbcb8 | 223 | *_bp = (const void *)*_bp + sizeof(*xdr); |
260a9803 DH |
224 | |
225 | if (vnode) { | |
dd9fbcb8 DH |
226 | if (test_bit(AFS_VNODE_UNSET, &vnode->flags)) |
227 | flags |= AFS_VNODE_NOT_YET_SET; | |
228 | afs_update_inode_from_status(vnode, status, expected_version, | |
229 | flags); | |
260a9803 DH |
230 | } |
231 | ||
c875c76a | 232 | return 0; |
dd9fbcb8 DH |
233 | |
234 | bad: | |
235 | xdr_dump_bad(*_bp); | |
c875c76a DH |
236 | return afs_protocol_error(call, -EBADMSG); |
237 | } | |
238 | ||
239 | /* | |
240 | * Decode the file status. We need to lock the target vnode if we're going to | |
241 | * update its status so that stat() sees the attributes update atomically. | |
242 | */ | |
243 | static int afs_decode_status(struct afs_call *call, | |
244 | const __be32 **_bp, | |
245 | struct afs_file_status *status, | |
246 | struct afs_vnode *vnode, | |
247 | const afs_dataversion_t *expected_version, | |
248 | struct afs_read *read_req) | |
249 | { | |
250 | int ret; | |
251 | ||
252 | if (!vnode) | |
253 | return xdr_decode_AFSFetchStatus(call, _bp, status, vnode, | |
254 | expected_version, read_req); | |
255 | ||
256 | write_seqlock(&vnode->cb_lock); | |
257 | ret = xdr_decode_AFSFetchStatus(call, _bp, status, vnode, | |
258 | expected_version, read_req); | |
259 | write_sequnlock(&vnode->cb_lock); | |
260 | return ret; | |
ec26815a | 261 | } |
1da177e4 | 262 | |
1da177e4 | 263 | /* |
08e0e7c8 | 264 | * decode an AFSCallBack block |
1da177e4 | 265 | */ |
c435ee34 DH |
266 | static void xdr_decode_AFSCallBack(struct afs_call *call, |
267 | struct afs_vnode *vnode, | |
268 | const __be32 **_bp) | |
1da177e4 | 269 | { |
d2ddc776 | 270 | struct afs_cb_interest *old, *cbi = call->cbi; |
08e0e7c8 | 271 | const __be32 *bp = *_bp; |
c435ee34 DH |
272 | u32 cb_expiry; |
273 | ||
274 | write_seqlock(&vnode->cb_lock); | |
275 | ||
68251f0a | 276 | if (call->cb_break == afs_cb_break_sum(vnode, cbi)) { |
c435ee34 DH |
277 | vnode->cb_version = ntohl(*bp++); |
278 | cb_expiry = ntohl(*bp++); | |
279 | vnode->cb_type = ntohl(*bp++); | |
280 | vnode->cb_expires_at = cb_expiry + ktime_get_real_seconds(); | |
d2ddc776 DH |
281 | old = vnode->cb_interest; |
282 | if (old != call->cbi) { | |
283 | vnode->cb_interest = cbi; | |
284 | cbi = old; | |
285 | } | |
c435ee34 DH |
286 | set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); |
287 | } else { | |
288 | bp += 3; | |
289 | } | |
1da177e4 | 290 | |
c435ee34 | 291 | write_sequnlock(&vnode->cb_lock); |
d2ddc776 | 292 | call->cbi = cbi; |
08e0e7c8 | 293 | *_bp = bp; |
ec26815a | 294 | } |
1da177e4 | 295 | |
260a9803 DH |
296 | static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, |
297 | struct afs_callback *cb) | |
298 | { | |
299 | const __be32 *bp = *_bp; | |
300 | ||
301 | cb->version = ntohl(*bp++); | |
302 | cb->expiry = ntohl(*bp++); | |
303 | cb->type = ntohl(*bp++); | |
304 | *_bp = bp; | |
305 | } | |
306 | ||
1da177e4 | 307 | /* |
08e0e7c8 | 308 | * decode an AFSVolSync block |
1da177e4 | 309 | */ |
08e0e7c8 DH |
310 | static void xdr_decode_AFSVolSync(const __be32 **_bp, |
311 | struct afs_volsync *volsync) | |
1da177e4 | 312 | { |
08e0e7c8 | 313 | const __be32 *bp = *_bp; |
1da177e4 | 314 | |
08e0e7c8 DH |
315 | volsync->creation = ntohl(*bp++); |
316 | bp++; /* spare2 */ | |
317 | bp++; /* spare3 */ | |
318 | bp++; /* spare4 */ | |
319 | bp++; /* spare5 */ | |
320 | bp++; /* spare6 */ | |
321 | *_bp = bp; | |
322 | } | |
1da177e4 | 323 | |
31143d5d DH |
324 | /* |
325 | * encode the requested attributes into an AFSStoreStatus block | |
326 | */ | |
327 | static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) | |
328 | { | |
329 | __be32 *bp = *_bp; | |
330 | u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; | |
331 | ||
332 | mask = 0; | |
333 | if (attr->ia_valid & ATTR_MTIME) { | |
334 | mask |= AFS_SET_MTIME; | |
335 | mtime = attr->ia_mtime.tv_sec; | |
336 | } | |
337 | ||
338 | if (attr->ia_valid & ATTR_UID) { | |
339 | mask |= AFS_SET_OWNER; | |
a0a5386a | 340 | owner = from_kuid(&init_user_ns, attr->ia_uid); |
31143d5d DH |
341 | } |
342 | ||
343 | if (attr->ia_valid & ATTR_GID) { | |
344 | mask |= AFS_SET_GROUP; | |
a0a5386a | 345 | group = from_kgid(&init_user_ns, attr->ia_gid); |
31143d5d DH |
346 | } |
347 | ||
348 | if (attr->ia_valid & ATTR_MODE) { | |
349 | mask |= AFS_SET_MODE; | |
350 | mode = attr->ia_mode & S_IALLUGO; | |
351 | } | |
352 | ||
353 | *bp++ = htonl(mask); | |
354 | *bp++ = htonl(mtime); | |
355 | *bp++ = htonl(owner); | |
356 | *bp++ = htonl(group); | |
357 | *bp++ = htonl(mode); | |
358 | *bp++ = 0; /* segment size */ | |
359 | *_bp = bp; | |
360 | } | |
361 | ||
45222b9e DH |
362 | /* |
363 | * decode an AFSFetchVolumeStatus block | |
364 | */ | |
365 | static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, | |
366 | struct afs_volume_status *vs) | |
367 | { | |
368 | const __be32 *bp = *_bp; | |
369 | ||
370 | vs->vid = ntohl(*bp++); | |
371 | vs->parent_id = ntohl(*bp++); | |
372 | vs->online = ntohl(*bp++); | |
373 | vs->in_service = ntohl(*bp++); | |
374 | vs->blessed = ntohl(*bp++); | |
375 | vs->needs_salvage = ntohl(*bp++); | |
376 | vs->type = ntohl(*bp++); | |
377 | vs->min_quota = ntohl(*bp++); | |
378 | vs->max_quota = ntohl(*bp++); | |
379 | vs->blocks_in_use = ntohl(*bp++); | |
380 | vs->part_blocks_avail = ntohl(*bp++); | |
381 | vs->part_max_blocks = ntohl(*bp++); | |
382 | *_bp = bp; | |
383 | } | |
384 | ||
08e0e7c8 DH |
385 | /* |
386 | * deliver reply data to an FS.FetchStatus | |
387 | */ | |
5cf9dd55 | 388 | static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call) |
08e0e7c8 | 389 | { |
97e3043a | 390 | struct afs_vnode *vnode = call->reply[0]; |
08e0e7c8 | 391 | const __be32 *bp; |
372ee163 | 392 | int ret; |
1da177e4 | 393 | |
d001648e | 394 | ret = afs_transfer_reply(call); |
372ee163 DH |
395 | if (ret < 0) |
396 | return ret; | |
1da177e4 | 397 | |
c435ee34 DH |
398 | _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); |
399 | ||
08e0e7c8 DH |
400 | /* unmarshall the reply once we've received all of it */ |
401 | bp = call->buffer; | |
c875c76a DH |
402 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
403 | &call->expected_version, NULL) < 0) | |
5f702c8e | 404 | return afs_protocol_error(call, -EBADMSG); |
c435ee34 | 405 | xdr_decode_AFSCallBack(call, vnode, &bp); |
97e3043a DH |
406 | if (call->reply[1]) |
407 | xdr_decode_AFSVolSync(&bp, call->reply[1]); | |
1da177e4 | 408 | |
08e0e7c8 DH |
409 | _leave(" = 0 [done]"); |
410 | return 0; | |
ec26815a | 411 | } |
08e0e7c8 DH |
412 | |
413 | /* | |
414 | * FS.FetchStatus operation type | |
415 | */ | |
5cf9dd55 DH |
416 | static const struct afs_call_type afs_RXFSFetchStatus_vnode = { |
417 | .name = "FS.FetchStatus(vnode)", | |
025db80c | 418 | .op = afs_FS_FetchStatus, |
5cf9dd55 | 419 | .deliver = afs_deliver_fs_fetch_status_vnode, |
08e0e7c8 DH |
420 | .destructor = afs_flat_call_destructor, |
421 | }; | |
1da177e4 | 422 | |
1da177e4 LT |
423 | /* |
424 | * fetch the status information for a file | |
425 | */ | |
0c3a5ac2 DH |
426 | int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync, |
427 | bool new_inode) | |
1da177e4 | 428 | { |
d2ddc776 | 429 | struct afs_vnode *vnode = fc->vnode; |
08e0e7c8 | 430 | struct afs_call *call; |
f044c884 | 431 | struct afs_net *net = afs_v2net(vnode); |
1da177e4 LT |
432 | __be32 *bp; |
433 | ||
416351f2 | 434 | _enter(",%x,{%x:%u},,", |
d2ddc776 | 435 | key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); |
1da177e4 | 436 | |
5cf9dd55 DH |
437 | call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode, |
438 | 16, (21 + 3 + 6) * 4); | |
d2ddc776 DH |
439 | if (!call) { |
440 | fc->ac.error = -ENOMEM; | |
08e0e7c8 | 441 | return -ENOMEM; |
d2ddc776 | 442 | } |
1da177e4 | 443 | |
d2ddc776 | 444 | call->key = fc->key; |
97e3043a DH |
445 | call->reply[0] = vnode; |
446 | call->reply[1] = volsync; | |
0c3a5ac2 | 447 | call->expected_version = new_inode ? 1 : vnode->status.data_version; |
1da177e4 LT |
448 | |
449 | /* marshall the parameters */ | |
08e0e7c8 | 450 | bp = call->request; |
1da177e4 LT |
451 | bp[0] = htonl(FSFETCHSTATUS); |
452 | bp[1] = htonl(vnode->fid.vid); | |
453 | bp[2] = htonl(vnode->fid.vnode); | |
454 | bp[3] = htonl(vnode->fid.unique); | |
455 | ||
d2ddc776 DH |
456 | call->cb_break = fc->cb_break; |
457 | afs_use_fs_server(call, fc->cbi); | |
025db80c | 458 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 459 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
ec26815a | 460 | } |
1da177e4 | 461 | |
1da177e4 | 462 | /* |
08e0e7c8 | 463 | * deliver reply data to an FS.FetchData |
1da177e4 | 464 | */ |
d001648e | 465 | static int afs_deliver_fs_fetch_data(struct afs_call *call) |
1da177e4 | 466 | { |
97e3043a DH |
467 | struct afs_vnode *vnode = call->reply[0]; |
468 | struct afs_read *req = call->reply[2]; | |
08e0e7c8 | 469 | const __be32 *bp; |
196ee9cd | 470 | unsigned int size; |
08e0e7c8 | 471 | void *buffer; |
1da177e4 | 472 | int ret; |
1da177e4 | 473 | |
6a0e3999 | 474 | _enter("{%u,%zu/%u;%llu/%llu}", |
196ee9cd DH |
475 | call->unmarshall, call->offset, call->count, |
476 | req->remain, req->actual_len); | |
08e0e7c8 DH |
477 | |
478 | switch (call->unmarshall) { | |
479 | case 0: | |
196ee9cd | 480 | req->actual_len = 0; |
08e0e7c8 DH |
481 | call->offset = 0; |
482 | call->unmarshall++; | |
b9b1f8d5 DH |
483 | if (call->operation_ID != FSFETCHDATA64) { |
484 | call->unmarshall++; | |
485 | goto no_msw; | |
486 | } | |
08e0e7c8 | 487 | |
b9b1f8d5 DH |
488 | /* extract the upper part of the returned data length of an |
489 | * FSFETCHDATA64 op (which should always be 0 using this | |
490 | * client) */ | |
08e0e7c8 | 491 | case 1: |
b9b1f8d5 | 492 | _debug("extract data length (MSW)"); |
d001648e | 493 | ret = afs_extract_data(call, &call->tmp, 4, true); |
372ee163 DH |
494 | if (ret < 0) |
495 | return ret; | |
b9b1f8d5 | 496 | |
196ee9cd DH |
497 | req->actual_len = ntohl(call->tmp); |
498 | req->actual_len <<= 32; | |
b9b1f8d5 DH |
499 | call->offset = 0; |
500 | call->unmarshall++; | |
501 | ||
502 | no_msw: | |
503 | /* extract the returned data length */ | |
504 | case 2: | |
08e0e7c8 | 505 | _debug("extract data length"); |
d001648e | 506 | ret = afs_extract_data(call, &call->tmp, 4, true); |
372ee163 DH |
507 | if (ret < 0) |
508 | return ret; | |
1da177e4 | 509 | |
196ee9cd DH |
510 | req->actual_len |= ntohl(call->tmp); |
511 | _debug("DATA length: %llu", req->actual_len); | |
196ee9cd DH |
512 | |
513 | req->remain = req->actual_len; | |
514 | call->offset = req->pos & (PAGE_SIZE - 1); | |
515 | req->index = 0; | |
516 | if (req->actual_len == 0) | |
517 | goto no_more_data; | |
08e0e7c8 DH |
518 | call->unmarshall++; |
519 | ||
196ee9cd | 520 | begin_page: |
6db3ac3c | 521 | ASSERTCMP(req->index, <, req->nr_pages); |
196ee9cd DH |
522 | if (req->remain > PAGE_SIZE - call->offset) |
523 | size = PAGE_SIZE - call->offset; | |
524 | else | |
525 | size = req->remain; | |
526 | call->count = call->offset + size; | |
527 | ASSERTCMP(call->count, <=, PAGE_SIZE); | |
528 | req->remain -= size; | |
529 | ||
08e0e7c8 | 530 | /* extract the returned data */ |
b9b1f8d5 | 531 | case 3: |
6a0e3999 | 532 | _debug("extract data %llu/%llu %zu/%u", |
196ee9cd DH |
533 | req->remain, req->actual_len, call->offset, call->count); |
534 | ||
535 | buffer = kmap(req->pages[req->index]); | |
536 | ret = afs_extract_data(call, buffer, call->count, true); | |
537 | kunmap(req->pages[req->index]); | |
538 | if (ret < 0) | |
539 | return ret; | |
540 | if (call->offset == PAGE_SIZE) { | |
541 | if (req->page_done) | |
542 | req->page_done(call, req); | |
29f06985 | 543 | req->index++; |
196ee9cd | 544 | if (req->remain > 0) { |
196ee9cd | 545 | call->offset = 0; |
e8e581a8 DH |
546 | if (req->index >= req->nr_pages) { |
547 | call->unmarshall = 4; | |
6db3ac3c | 548 | goto begin_discard; |
e8e581a8 | 549 | } |
196ee9cd DH |
550 | goto begin_page; |
551 | } | |
08e0e7c8 | 552 | } |
6db3ac3c DH |
553 | goto no_more_data; |
554 | ||
555 | /* Discard any excess data the server gave us */ | |
556 | begin_discard: | |
557 | case 4: | |
6a0e3999 | 558 | size = min_t(loff_t, sizeof(afs_discard_buffer), req->remain); |
6db3ac3c | 559 | call->count = size; |
6a0e3999 | 560 | _debug("extract discard %llu/%llu %zu/%u", |
6db3ac3c DH |
561 | req->remain, req->actual_len, call->offset, call->count); |
562 | ||
563 | call->offset = 0; | |
564 | ret = afs_extract_data(call, afs_discard_buffer, call->count, true); | |
565 | req->remain -= call->offset; | |
566 | if (ret < 0) | |
567 | return ret; | |
568 | if (req->remain > 0) | |
569 | goto begin_discard; | |
1da177e4 | 570 | |
196ee9cd | 571 | no_more_data: |
08e0e7c8 | 572 | call->offset = 0; |
6db3ac3c | 573 | call->unmarshall = 5; |
1da177e4 | 574 | |
08e0e7c8 | 575 | /* extract the metadata */ |
6db3ac3c | 576 | case 5: |
d001648e DH |
577 | ret = afs_extract_data(call, call->buffer, |
578 | (21 + 3 + 6) * 4, false); | |
372ee163 DH |
579 | if (ret < 0) |
580 | return ret; | |
08e0e7c8 DH |
581 | |
582 | bp = call->buffer; | |
c875c76a DH |
583 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
584 | &vnode->status.data_version, req) < 0) | |
5f702c8e | 585 | return afs_protocol_error(call, -EBADMSG); |
c435ee34 | 586 | xdr_decode_AFSCallBack(call, vnode, &bp); |
97e3043a DH |
587 | if (call->reply[1]) |
588 | xdr_decode_AFSVolSync(&bp, call->reply[1]); | |
08e0e7c8 DH |
589 | |
590 | call->offset = 0; | |
591 | call->unmarshall++; | |
1da177e4 | 592 | |
6db3ac3c | 593 | case 6: |
08e0e7c8 | 594 | break; |
1da177e4 LT |
595 | } |
596 | ||
6db3ac3c DH |
597 | for (; req->index < req->nr_pages; req->index++) { |
598 | if (call->count < PAGE_SIZE) | |
599 | zero_user_segment(req->pages[req->index], | |
600 | call->count, PAGE_SIZE); | |
196ee9cd DH |
601 | if (req->page_done) |
602 | req->page_done(call, req); | |
6db3ac3c | 603 | call->count = 0; |
416351f2 DH |
604 | } |
605 | ||
08e0e7c8 DH |
606 | _leave(" = 0 [done]"); |
607 | return 0; | |
ec26815a | 608 | } |
1da177e4 | 609 | |
196ee9cd DH |
610 | static void afs_fetch_data_destructor(struct afs_call *call) |
611 | { | |
97e3043a | 612 | struct afs_read *req = call->reply[2]; |
196ee9cd DH |
613 | |
614 | afs_put_read(req); | |
615 | afs_flat_call_destructor(call); | |
616 | } | |
617 | ||
1da177e4 | 618 | /* |
08e0e7c8 | 619 | * FS.FetchData operation type |
1da177e4 | 620 | */ |
08e0e7c8 | 621 | static const struct afs_call_type afs_RXFSFetchData = { |
00d3b7a4 | 622 | .name = "FS.FetchData", |
025db80c | 623 | .op = afs_FS_FetchData, |
08e0e7c8 | 624 | .deliver = afs_deliver_fs_fetch_data, |
196ee9cd | 625 | .destructor = afs_fetch_data_destructor, |
08e0e7c8 DH |
626 | }; |
627 | ||
b9b1f8d5 DH |
628 | static const struct afs_call_type afs_RXFSFetchData64 = { |
629 | .name = "FS.FetchData64", | |
025db80c | 630 | .op = afs_FS_FetchData64, |
b9b1f8d5 | 631 | .deliver = afs_deliver_fs_fetch_data, |
196ee9cd | 632 | .destructor = afs_fetch_data_destructor, |
b9b1f8d5 DH |
633 | }; |
634 | ||
635 | /* | |
636 | * fetch data from a very large file | |
637 | */ | |
d2ddc776 | 638 | static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) |
b9b1f8d5 | 639 | { |
d2ddc776 | 640 | struct afs_vnode *vnode = fc->vnode; |
b9b1f8d5 | 641 | struct afs_call *call; |
f044c884 | 642 | struct afs_net *net = afs_v2net(vnode); |
b9b1f8d5 DH |
643 | __be32 *bp; |
644 | ||
645 | _enter(""); | |
646 | ||
f044c884 | 647 | call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); |
b9b1f8d5 DH |
648 | if (!call) |
649 | return -ENOMEM; | |
650 | ||
d2ddc776 | 651 | call->key = fc->key; |
97e3043a DH |
652 | call->reply[0] = vnode; |
653 | call->reply[1] = NULL; /* volsync */ | |
654 | call->reply[2] = req; | |
0c3a5ac2 | 655 | call->expected_version = vnode->status.data_version; |
b9b1f8d5 DH |
656 | |
657 | /* marshall the parameters */ | |
658 | bp = call->request; | |
659 | bp[0] = htonl(FSFETCHDATA64); | |
660 | bp[1] = htonl(vnode->fid.vid); | |
661 | bp[2] = htonl(vnode->fid.vnode); | |
662 | bp[3] = htonl(vnode->fid.unique); | |
196ee9cd DH |
663 | bp[4] = htonl(upper_32_bits(req->pos)); |
664 | bp[5] = htonl(lower_32_bits(req->pos)); | |
b9b1f8d5 | 665 | bp[6] = 0; |
196ee9cd | 666 | bp[7] = htonl(lower_32_bits(req->len)); |
b9b1f8d5 | 667 | |
f3ddee8d | 668 | refcount_inc(&req->usage); |
d2ddc776 DH |
669 | call->cb_break = fc->cb_break; |
670 | afs_use_fs_server(call, fc->cbi); | |
025db80c | 671 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 672 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
b9b1f8d5 DH |
673 | } |
674 | ||
08e0e7c8 DH |
675 | /* |
676 | * fetch data from a file | |
677 | */ | |
d2ddc776 | 678 | int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) |
1da177e4 | 679 | { |
d2ddc776 | 680 | struct afs_vnode *vnode = fc->vnode; |
08e0e7c8 | 681 | struct afs_call *call; |
f044c884 | 682 | struct afs_net *net = afs_v2net(vnode); |
1da177e4 LT |
683 | __be32 *bp; |
684 | ||
196ee9cd DH |
685 | if (upper_32_bits(req->pos) || |
686 | upper_32_bits(req->len) || | |
687 | upper_32_bits(req->pos + req->len)) | |
d2ddc776 | 688 | return afs_fs_fetch_data64(fc, req); |
b9b1f8d5 | 689 | |
08e0e7c8 | 690 | _enter(""); |
1da177e4 | 691 | |
f044c884 | 692 | call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); |
08e0e7c8 DH |
693 | if (!call) |
694 | return -ENOMEM; | |
1da177e4 | 695 | |
d2ddc776 | 696 | call->key = fc->key; |
97e3043a DH |
697 | call->reply[0] = vnode; |
698 | call->reply[1] = NULL; /* volsync */ | |
699 | call->reply[2] = req; | |
0c3a5ac2 | 700 | call->expected_version = vnode->status.data_version; |
1da177e4 LT |
701 | |
702 | /* marshall the parameters */ | |
08e0e7c8 DH |
703 | bp = call->request; |
704 | bp[0] = htonl(FSFETCHDATA); | |
705 | bp[1] = htonl(vnode->fid.vid); | |
706 | bp[2] = htonl(vnode->fid.vnode); | |
707 | bp[3] = htonl(vnode->fid.unique); | |
196ee9cd DH |
708 | bp[4] = htonl(lower_32_bits(req->pos)); |
709 | bp[5] = htonl(lower_32_bits(req->len)); | |
1da177e4 | 710 | |
f3ddee8d | 711 | refcount_inc(&req->usage); |
d2ddc776 DH |
712 | call->cb_break = fc->cb_break; |
713 | afs_use_fs_server(call, fc->cbi); | |
025db80c | 714 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 715 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
ec26815a | 716 | } |
260a9803 DH |
717 | |
718 | /* | |
719 | * deliver reply data to an FS.CreateFile or an FS.MakeDir | |
720 | */ | |
d001648e | 721 | static int afs_deliver_fs_create_vnode(struct afs_call *call) |
260a9803 | 722 | { |
97e3043a | 723 | struct afs_vnode *vnode = call->reply[0]; |
260a9803 | 724 | const __be32 *bp; |
372ee163 | 725 | int ret; |
260a9803 | 726 | |
d001648e | 727 | _enter("{%u}", call->unmarshall); |
260a9803 | 728 | |
d001648e | 729 | ret = afs_transfer_reply(call); |
372ee163 DH |
730 | if (ret < 0) |
731 | return ret; | |
260a9803 DH |
732 | |
733 | /* unmarshall the reply once we've received all of it */ | |
734 | bp = call->buffer; | |
97e3043a | 735 | xdr_decode_AFSFid(&bp, call->reply[1]); |
c875c76a DH |
736 | if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 || |
737 | afs_decode_status(call, &bp, &vnode->status, vnode, | |
738 | &call->expected_version, NULL) < 0) | |
5f702c8e | 739 | return afs_protocol_error(call, -EBADMSG); |
97e3043a DH |
740 | xdr_decode_AFSCallBack_raw(&bp, call->reply[3]); |
741 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | |
260a9803 DH |
742 | |
743 | _leave(" = 0 [done]"); | |
744 | return 0; | |
745 | } | |
746 | ||
747 | /* | |
748 | * FS.CreateFile and FS.MakeDir operation type | |
749 | */ | |
025db80c DH |
750 | static const struct afs_call_type afs_RXFSCreateFile = { |
751 | .name = "FS.CreateFile", | |
752 | .op = afs_FS_CreateFile, | |
753 | .deliver = afs_deliver_fs_create_vnode, | |
754 | .destructor = afs_flat_call_destructor, | |
755 | }; | |
756 | ||
757 | static const struct afs_call_type afs_RXFSMakeDir = { | |
758 | .name = "FS.MakeDir", | |
759 | .op = afs_FS_MakeDir, | |
260a9803 | 760 | .deliver = afs_deliver_fs_create_vnode, |
260a9803 DH |
761 | .destructor = afs_flat_call_destructor, |
762 | }; | |
763 | ||
764 | /* | |
765 | * create a file or make a directory | |
766 | */ | |
8b2a464c | 767 | int afs_fs_create(struct afs_fs_cursor *fc, |
260a9803 DH |
768 | const char *name, |
769 | umode_t mode, | |
63a4681f | 770 | u64 current_data_version, |
260a9803 DH |
771 | struct afs_fid *newfid, |
772 | struct afs_file_status *newstatus, | |
d2ddc776 | 773 | struct afs_callback *newcb) |
260a9803 | 774 | { |
d2ddc776 | 775 | struct afs_vnode *vnode = fc->vnode; |
260a9803 | 776 | struct afs_call *call; |
f044c884 | 777 | struct afs_net *net = afs_v2net(vnode); |
260a9803 DH |
778 | size_t namesz, reqsz, padsz; |
779 | __be32 *bp; | |
780 | ||
781 | _enter(""); | |
782 | ||
783 | namesz = strlen(name); | |
784 | padsz = (4 - (namesz & 3)) & 3; | |
785 | reqsz = (5 * 4) + namesz + padsz + (6 * 4); | |
786 | ||
025db80c DH |
787 | call = afs_alloc_flat_call( |
788 | net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile, | |
789 | reqsz, (3 + 21 + 21 + 3 + 6) * 4); | |
260a9803 DH |
790 | if (!call) |
791 | return -ENOMEM; | |
792 | ||
d2ddc776 | 793 | call->key = fc->key; |
97e3043a DH |
794 | call->reply[0] = vnode; |
795 | call->reply[1] = newfid; | |
796 | call->reply[2] = newstatus; | |
797 | call->reply[3] = newcb; | |
63a4681f | 798 | call->expected_version = current_data_version + 1; |
260a9803 DH |
799 | |
800 | /* marshall the parameters */ | |
801 | bp = call->request; | |
802 | *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); | |
803 | *bp++ = htonl(vnode->fid.vid); | |
804 | *bp++ = htonl(vnode->fid.vnode); | |
805 | *bp++ = htonl(vnode->fid.unique); | |
806 | *bp++ = htonl(namesz); | |
807 | memcpy(bp, name, namesz); | |
808 | bp = (void *) bp + namesz; | |
809 | if (padsz > 0) { | |
810 | memset(bp, 0, padsz); | |
811 | bp = (void *) bp + padsz; | |
812 | } | |
ab94f5d0 MD |
813 | *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); |
814 | *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ | |
260a9803 DH |
815 | *bp++ = 0; /* owner */ |
816 | *bp++ = 0; /* group */ | |
817 | *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ | |
818 | *bp++ = 0; /* segment size */ | |
819 | ||
d2ddc776 | 820 | afs_use_fs_server(call, fc->cbi); |
025db80c | 821 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 822 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
260a9803 DH |
823 | } |
824 | ||
825 | /* | |
826 | * deliver reply data to an FS.RemoveFile or FS.RemoveDir | |
827 | */ | |
d001648e | 828 | static int afs_deliver_fs_remove(struct afs_call *call) |
260a9803 | 829 | { |
97e3043a | 830 | struct afs_vnode *vnode = call->reply[0]; |
260a9803 | 831 | const __be32 *bp; |
372ee163 | 832 | int ret; |
260a9803 | 833 | |
d001648e | 834 | _enter("{%u}", call->unmarshall); |
260a9803 | 835 | |
d001648e | 836 | ret = afs_transfer_reply(call); |
372ee163 DH |
837 | if (ret < 0) |
838 | return ret; | |
260a9803 DH |
839 | |
840 | /* unmarshall the reply once we've received all of it */ | |
841 | bp = call->buffer; | |
c875c76a DH |
842 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
843 | &call->expected_version, NULL) < 0) | |
5f702c8e | 844 | return afs_protocol_error(call, -EBADMSG); |
97e3043a | 845 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
260a9803 DH |
846 | |
847 | _leave(" = 0 [done]"); | |
848 | return 0; | |
849 | } | |
850 | ||
851 | /* | |
852 | * FS.RemoveDir/FS.RemoveFile operation type | |
853 | */ | |
025db80c DH |
854 | static const struct afs_call_type afs_RXFSRemoveFile = { |
855 | .name = "FS.RemoveFile", | |
856 | .op = afs_FS_RemoveFile, | |
857 | .deliver = afs_deliver_fs_remove, | |
858 | .destructor = afs_flat_call_destructor, | |
859 | }; | |
860 | ||
861 | static const struct afs_call_type afs_RXFSRemoveDir = { | |
862 | .name = "FS.RemoveDir", | |
863 | .op = afs_FS_RemoveDir, | |
260a9803 | 864 | .deliver = afs_deliver_fs_remove, |
260a9803 DH |
865 | .destructor = afs_flat_call_destructor, |
866 | }; | |
867 | ||
868 | /* | |
869 | * remove a file or directory | |
870 | */ | |
63a4681f DH |
871 | int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir, |
872 | u64 current_data_version) | |
260a9803 | 873 | { |
d2ddc776 | 874 | struct afs_vnode *vnode = fc->vnode; |
260a9803 | 875 | struct afs_call *call; |
f044c884 | 876 | struct afs_net *net = afs_v2net(vnode); |
260a9803 DH |
877 | size_t namesz, reqsz, padsz; |
878 | __be32 *bp; | |
879 | ||
880 | _enter(""); | |
881 | ||
882 | namesz = strlen(name); | |
883 | padsz = (4 - (namesz & 3)) & 3; | |
884 | reqsz = (5 * 4) + namesz + padsz; | |
885 | ||
025db80c DH |
886 | call = afs_alloc_flat_call( |
887 | net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile, | |
888 | reqsz, (21 + 6) * 4); | |
260a9803 DH |
889 | if (!call) |
890 | return -ENOMEM; | |
891 | ||
d2ddc776 | 892 | call->key = fc->key; |
97e3043a | 893 | call->reply[0] = vnode; |
63a4681f | 894 | call->expected_version = current_data_version + 1; |
260a9803 DH |
895 | |
896 | /* marshall the parameters */ | |
897 | bp = call->request; | |
898 | *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); | |
899 | *bp++ = htonl(vnode->fid.vid); | |
900 | *bp++ = htonl(vnode->fid.vnode); | |
901 | *bp++ = htonl(vnode->fid.unique); | |
902 | *bp++ = htonl(namesz); | |
903 | memcpy(bp, name, namesz); | |
904 | bp = (void *) bp + namesz; | |
905 | if (padsz > 0) { | |
906 | memset(bp, 0, padsz); | |
907 | bp = (void *) bp + padsz; | |
908 | } | |
909 | ||
d2ddc776 | 910 | afs_use_fs_server(call, fc->cbi); |
025db80c | 911 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 912 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
260a9803 DH |
913 | } |
914 | ||
915 | /* | |
916 | * deliver reply data to an FS.Link | |
917 | */ | |
d001648e | 918 | static int afs_deliver_fs_link(struct afs_call *call) |
260a9803 | 919 | { |
97e3043a | 920 | struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1]; |
260a9803 | 921 | const __be32 *bp; |
372ee163 | 922 | int ret; |
260a9803 | 923 | |
d001648e | 924 | _enter("{%u}", call->unmarshall); |
260a9803 | 925 | |
d001648e | 926 | ret = afs_transfer_reply(call); |
372ee163 DH |
927 | if (ret < 0) |
928 | return ret; | |
260a9803 DH |
929 | |
930 | /* unmarshall the reply once we've received all of it */ | |
931 | bp = call->buffer; | |
c875c76a DH |
932 | if (afs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 || |
933 | afs_decode_status(call, &bp, &dvnode->status, dvnode, | |
934 | &call->expected_version, NULL) < 0) | |
5f702c8e | 935 | return afs_protocol_error(call, -EBADMSG); |
97e3043a | 936 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
260a9803 DH |
937 | |
938 | _leave(" = 0 [done]"); | |
939 | return 0; | |
940 | } | |
941 | ||
942 | /* | |
943 | * FS.Link operation type | |
944 | */ | |
945 | static const struct afs_call_type afs_RXFSLink = { | |
946 | .name = "FS.Link", | |
025db80c | 947 | .op = afs_FS_Link, |
260a9803 | 948 | .deliver = afs_deliver_fs_link, |
260a9803 DH |
949 | .destructor = afs_flat_call_destructor, |
950 | }; | |
951 | ||
952 | /* | |
953 | * make a hard link | |
954 | */ | |
d2ddc776 | 955 | int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, |
63a4681f | 956 | const char *name, u64 current_data_version) |
260a9803 | 957 | { |
d2ddc776 | 958 | struct afs_vnode *dvnode = fc->vnode; |
260a9803 | 959 | struct afs_call *call; |
f044c884 | 960 | struct afs_net *net = afs_v2net(vnode); |
260a9803 DH |
961 | size_t namesz, reqsz, padsz; |
962 | __be32 *bp; | |
963 | ||
964 | _enter(""); | |
965 | ||
966 | namesz = strlen(name); | |
967 | padsz = (4 - (namesz & 3)) & 3; | |
968 | reqsz = (5 * 4) + namesz + padsz + (3 * 4); | |
969 | ||
f044c884 | 970 | call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); |
260a9803 DH |
971 | if (!call) |
972 | return -ENOMEM; | |
973 | ||
d2ddc776 | 974 | call->key = fc->key; |
97e3043a DH |
975 | call->reply[0] = dvnode; |
976 | call->reply[1] = vnode; | |
63a4681f | 977 | call->expected_version = current_data_version + 1; |
260a9803 DH |
978 | |
979 | /* marshall the parameters */ | |
980 | bp = call->request; | |
981 | *bp++ = htonl(FSLINK); | |
982 | *bp++ = htonl(dvnode->fid.vid); | |
983 | *bp++ = htonl(dvnode->fid.vnode); | |
984 | *bp++ = htonl(dvnode->fid.unique); | |
985 | *bp++ = htonl(namesz); | |
986 | memcpy(bp, name, namesz); | |
987 | bp = (void *) bp + namesz; | |
988 | if (padsz > 0) { | |
989 | memset(bp, 0, padsz); | |
990 | bp = (void *) bp + padsz; | |
991 | } | |
992 | *bp++ = htonl(vnode->fid.vid); | |
993 | *bp++ = htonl(vnode->fid.vnode); | |
994 | *bp++ = htonl(vnode->fid.unique); | |
995 | ||
d2ddc776 | 996 | afs_use_fs_server(call, fc->cbi); |
025db80c | 997 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 998 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
260a9803 DH |
999 | } |
1000 | ||
1001 | /* | |
1002 | * deliver reply data to an FS.Symlink | |
1003 | */ | |
d001648e | 1004 | static int afs_deliver_fs_symlink(struct afs_call *call) |
260a9803 | 1005 | { |
97e3043a | 1006 | struct afs_vnode *vnode = call->reply[0]; |
260a9803 | 1007 | const __be32 *bp; |
372ee163 | 1008 | int ret; |
260a9803 | 1009 | |
d001648e | 1010 | _enter("{%u}", call->unmarshall); |
260a9803 | 1011 | |
d001648e | 1012 | ret = afs_transfer_reply(call); |
372ee163 DH |
1013 | if (ret < 0) |
1014 | return ret; | |
260a9803 DH |
1015 | |
1016 | /* unmarshall the reply once we've received all of it */ | |
1017 | bp = call->buffer; | |
97e3043a | 1018 | xdr_decode_AFSFid(&bp, call->reply[1]); |
c875c76a DH |
1019 | if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) || |
1020 | afs_decode_status(call, &bp, &vnode->status, vnode, | |
1021 | &call->expected_version, NULL) < 0) | |
5f702c8e | 1022 | return afs_protocol_error(call, -EBADMSG); |
97e3043a | 1023 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
260a9803 DH |
1024 | |
1025 | _leave(" = 0 [done]"); | |
1026 | return 0; | |
1027 | } | |
1028 | ||
1029 | /* | |
1030 | * FS.Symlink operation type | |
1031 | */ | |
1032 | static const struct afs_call_type afs_RXFSSymlink = { | |
1033 | .name = "FS.Symlink", | |
025db80c | 1034 | .op = afs_FS_Symlink, |
260a9803 | 1035 | .deliver = afs_deliver_fs_symlink, |
260a9803 DH |
1036 | .destructor = afs_flat_call_destructor, |
1037 | }; | |
1038 | ||
1039 | /* | |
1040 | * create a symbolic link | |
1041 | */ | |
8b2a464c | 1042 | int afs_fs_symlink(struct afs_fs_cursor *fc, |
260a9803 DH |
1043 | const char *name, |
1044 | const char *contents, | |
63a4681f | 1045 | u64 current_data_version, |
260a9803 | 1046 | struct afs_fid *newfid, |
d2ddc776 | 1047 | struct afs_file_status *newstatus) |
260a9803 | 1048 | { |
d2ddc776 | 1049 | struct afs_vnode *vnode = fc->vnode; |
260a9803 | 1050 | struct afs_call *call; |
f044c884 | 1051 | struct afs_net *net = afs_v2net(vnode); |
260a9803 DH |
1052 | size_t namesz, reqsz, padsz, c_namesz, c_padsz; |
1053 | __be32 *bp; | |
1054 | ||
1055 | _enter(""); | |
1056 | ||
1057 | namesz = strlen(name); | |
1058 | padsz = (4 - (namesz & 3)) & 3; | |
1059 | ||
1060 | c_namesz = strlen(contents); | |
1061 | c_padsz = (4 - (c_namesz & 3)) & 3; | |
1062 | ||
1063 | reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); | |
1064 | ||
f044c884 | 1065 | call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz, |
260a9803 DH |
1066 | (3 + 21 + 21 + 6) * 4); |
1067 | if (!call) | |
1068 | return -ENOMEM; | |
1069 | ||
d2ddc776 | 1070 | call->key = fc->key; |
97e3043a DH |
1071 | call->reply[0] = vnode; |
1072 | call->reply[1] = newfid; | |
1073 | call->reply[2] = newstatus; | |
63a4681f | 1074 | call->expected_version = current_data_version + 1; |
260a9803 DH |
1075 | |
1076 | /* marshall the parameters */ | |
1077 | bp = call->request; | |
1078 | *bp++ = htonl(FSSYMLINK); | |
1079 | *bp++ = htonl(vnode->fid.vid); | |
1080 | *bp++ = htonl(vnode->fid.vnode); | |
1081 | *bp++ = htonl(vnode->fid.unique); | |
1082 | *bp++ = htonl(namesz); | |
1083 | memcpy(bp, name, namesz); | |
1084 | bp = (void *) bp + namesz; | |
1085 | if (padsz > 0) { | |
1086 | memset(bp, 0, padsz); | |
1087 | bp = (void *) bp + padsz; | |
1088 | } | |
1089 | *bp++ = htonl(c_namesz); | |
1090 | memcpy(bp, contents, c_namesz); | |
1091 | bp = (void *) bp + c_namesz; | |
1092 | if (c_padsz > 0) { | |
1093 | memset(bp, 0, c_padsz); | |
1094 | bp = (void *) bp + c_padsz; | |
1095 | } | |
ab94f5d0 MD |
1096 | *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); |
1097 | *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ | |
260a9803 DH |
1098 | *bp++ = 0; /* owner */ |
1099 | *bp++ = 0; /* group */ | |
1100 | *bp++ = htonl(S_IRWXUGO); /* unix mode */ | |
1101 | *bp++ = 0; /* segment size */ | |
1102 | ||
d2ddc776 | 1103 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1104 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1105 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
260a9803 DH |
1106 | } |
1107 | ||
1108 | /* | |
1109 | * deliver reply data to an FS.Rename | |
1110 | */ | |
d001648e | 1111 | static int afs_deliver_fs_rename(struct afs_call *call) |
260a9803 | 1112 | { |
97e3043a | 1113 | struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1]; |
260a9803 | 1114 | const __be32 *bp; |
372ee163 | 1115 | int ret; |
260a9803 | 1116 | |
d001648e | 1117 | _enter("{%u}", call->unmarshall); |
260a9803 | 1118 | |
d001648e | 1119 | ret = afs_transfer_reply(call); |
372ee163 DH |
1120 | if (ret < 0) |
1121 | return ret; | |
260a9803 DH |
1122 | |
1123 | /* unmarshall the reply once we've received all of it */ | |
1124 | bp = call->buffer; | |
c875c76a DH |
1125 | if (afs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode, |
1126 | &call->expected_version, NULL) < 0) | |
5f702c8e | 1127 | return afs_protocol_error(call, -EBADMSG); |
dd9fbcb8 | 1128 | if (new_dvnode != orig_dvnode && |
c875c76a DH |
1129 | afs_decode_status(call, &bp, &new_dvnode->status, new_dvnode, |
1130 | &call->expected_version_2, NULL) < 0) | |
5f702c8e | 1131 | return afs_protocol_error(call, -EBADMSG); |
97e3043a | 1132 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
260a9803 DH |
1133 | |
1134 | _leave(" = 0 [done]"); | |
1135 | return 0; | |
1136 | } | |
1137 | ||
1138 | /* | |
1139 | * FS.Rename operation type | |
1140 | */ | |
1141 | static const struct afs_call_type afs_RXFSRename = { | |
1142 | .name = "FS.Rename", | |
025db80c | 1143 | .op = afs_FS_Rename, |
260a9803 | 1144 | .deliver = afs_deliver_fs_rename, |
260a9803 DH |
1145 | .destructor = afs_flat_call_destructor, |
1146 | }; | |
1147 | ||
1148 | /* | |
1149 | * create a symbolic link | |
1150 | */ | |
8b2a464c | 1151 | int afs_fs_rename(struct afs_fs_cursor *fc, |
260a9803 DH |
1152 | const char *orig_name, |
1153 | struct afs_vnode *new_dvnode, | |
63a4681f DH |
1154 | const char *new_name, |
1155 | u64 current_orig_data_version, | |
1156 | u64 current_new_data_version) | |
260a9803 | 1157 | { |
d2ddc776 | 1158 | struct afs_vnode *orig_dvnode = fc->vnode; |
260a9803 | 1159 | struct afs_call *call; |
f044c884 | 1160 | struct afs_net *net = afs_v2net(orig_dvnode); |
260a9803 DH |
1161 | size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; |
1162 | __be32 *bp; | |
1163 | ||
1164 | _enter(""); | |
1165 | ||
1166 | o_namesz = strlen(orig_name); | |
1167 | o_padsz = (4 - (o_namesz & 3)) & 3; | |
1168 | ||
1169 | n_namesz = strlen(new_name); | |
1170 | n_padsz = (4 - (n_namesz & 3)) & 3; | |
1171 | ||
1172 | reqsz = (4 * 4) + | |
1173 | 4 + o_namesz + o_padsz + | |
1174 | (3 * 4) + | |
1175 | 4 + n_namesz + n_padsz; | |
1176 | ||
f044c884 | 1177 | call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); |
260a9803 DH |
1178 | if (!call) |
1179 | return -ENOMEM; | |
1180 | ||
d2ddc776 | 1181 | call->key = fc->key; |
97e3043a DH |
1182 | call->reply[0] = orig_dvnode; |
1183 | call->reply[1] = new_dvnode; | |
63a4681f DH |
1184 | call->expected_version = current_orig_data_version + 1; |
1185 | call->expected_version_2 = current_new_data_version + 1; | |
260a9803 DH |
1186 | |
1187 | /* marshall the parameters */ | |
1188 | bp = call->request; | |
1189 | *bp++ = htonl(FSRENAME); | |
1190 | *bp++ = htonl(orig_dvnode->fid.vid); | |
1191 | *bp++ = htonl(orig_dvnode->fid.vnode); | |
1192 | *bp++ = htonl(orig_dvnode->fid.unique); | |
1193 | *bp++ = htonl(o_namesz); | |
1194 | memcpy(bp, orig_name, o_namesz); | |
1195 | bp = (void *) bp + o_namesz; | |
1196 | if (o_padsz > 0) { | |
1197 | memset(bp, 0, o_padsz); | |
1198 | bp = (void *) bp + o_padsz; | |
1199 | } | |
1200 | ||
1201 | *bp++ = htonl(new_dvnode->fid.vid); | |
1202 | *bp++ = htonl(new_dvnode->fid.vnode); | |
1203 | *bp++ = htonl(new_dvnode->fid.unique); | |
1204 | *bp++ = htonl(n_namesz); | |
1205 | memcpy(bp, new_name, n_namesz); | |
1206 | bp = (void *) bp + n_namesz; | |
1207 | if (n_padsz > 0) { | |
1208 | memset(bp, 0, n_padsz); | |
1209 | bp = (void *) bp + n_padsz; | |
1210 | } | |
1211 | ||
d2ddc776 | 1212 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1213 | trace_afs_make_fs_call(call, &orig_dvnode->fid); |
d2ddc776 | 1214 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
260a9803 | 1215 | } |
31143d5d DH |
1216 | |
1217 | /* | |
1218 | * deliver reply data to an FS.StoreData | |
1219 | */ | |
d001648e | 1220 | static int afs_deliver_fs_store_data(struct afs_call *call) |
31143d5d | 1221 | { |
97e3043a | 1222 | struct afs_vnode *vnode = call->reply[0]; |
31143d5d | 1223 | const __be32 *bp; |
372ee163 | 1224 | int ret; |
31143d5d | 1225 | |
d001648e | 1226 | _enter(""); |
31143d5d | 1227 | |
d001648e | 1228 | ret = afs_transfer_reply(call); |
372ee163 DH |
1229 | if (ret < 0) |
1230 | return ret; | |
31143d5d DH |
1231 | |
1232 | /* unmarshall the reply once we've received all of it */ | |
1233 | bp = call->buffer; | |
c875c76a DH |
1234 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
1235 | &call->expected_version, NULL) < 0) | |
5f702c8e | 1236 | return afs_protocol_error(call, -EBADMSG); |
97e3043a | 1237 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
31143d5d DH |
1238 | |
1239 | afs_pages_written_back(vnode, call); | |
1240 | ||
1241 | _leave(" = 0 [done]"); | |
1242 | return 0; | |
1243 | } | |
1244 | ||
1245 | /* | |
1246 | * FS.StoreData operation type | |
1247 | */ | |
1248 | static const struct afs_call_type afs_RXFSStoreData = { | |
1249 | .name = "FS.StoreData", | |
025db80c | 1250 | .op = afs_FS_StoreData, |
31143d5d | 1251 | .deliver = afs_deliver_fs_store_data, |
31143d5d DH |
1252 | .destructor = afs_flat_call_destructor, |
1253 | }; | |
1254 | ||
b9b1f8d5 DH |
1255 | static const struct afs_call_type afs_RXFSStoreData64 = { |
1256 | .name = "FS.StoreData64", | |
025db80c | 1257 | .op = afs_FS_StoreData64, |
b9b1f8d5 | 1258 | .deliver = afs_deliver_fs_store_data, |
b9b1f8d5 DH |
1259 | .destructor = afs_flat_call_destructor, |
1260 | }; | |
1261 | ||
1262 | /* | |
1263 | * store a set of pages to a very large file | |
1264 | */ | |
8b2a464c | 1265 | static int afs_fs_store_data64(struct afs_fs_cursor *fc, |
4343d008 | 1266 | struct address_space *mapping, |
b9b1f8d5 DH |
1267 | pgoff_t first, pgoff_t last, |
1268 | unsigned offset, unsigned to, | |
d2ddc776 | 1269 | loff_t size, loff_t pos, loff_t i_size) |
b9b1f8d5 | 1270 | { |
4343d008 | 1271 | struct afs_vnode *vnode = fc->vnode; |
b9b1f8d5 | 1272 | struct afs_call *call; |
f044c884 | 1273 | struct afs_net *net = afs_v2net(vnode); |
b9b1f8d5 DH |
1274 | __be32 *bp; |
1275 | ||
1276 | _enter(",%x,{%x:%u},,", | |
4343d008 | 1277 | key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); |
b9b1f8d5 | 1278 | |
f044c884 | 1279 | call = afs_alloc_flat_call(net, &afs_RXFSStoreData64, |
b9b1f8d5 DH |
1280 | (4 + 6 + 3 * 2) * 4, |
1281 | (21 + 6) * 4); | |
1282 | if (!call) | |
1283 | return -ENOMEM; | |
1284 | ||
4343d008 DH |
1285 | call->key = fc->key; |
1286 | call->mapping = mapping; | |
97e3043a | 1287 | call->reply[0] = vnode; |
b9b1f8d5 DH |
1288 | call->first = first; |
1289 | call->last = last; | |
1290 | call->first_offset = offset; | |
1291 | call->last_to = to; | |
1292 | call->send_pages = true; | |
0c3a5ac2 | 1293 | call->expected_version = vnode->status.data_version + 1; |
b9b1f8d5 DH |
1294 | |
1295 | /* marshall the parameters */ | |
1296 | bp = call->request; | |
1297 | *bp++ = htonl(FSSTOREDATA64); | |
1298 | *bp++ = htonl(vnode->fid.vid); | |
1299 | *bp++ = htonl(vnode->fid.vnode); | |
1300 | *bp++ = htonl(vnode->fid.unique); | |
1301 | ||
ab94f5d0 MD |
1302 | *bp++ = htonl(AFS_SET_MTIME); /* mask */ |
1303 | *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ | |
b9b1f8d5 DH |
1304 | *bp++ = 0; /* owner */ |
1305 | *bp++ = 0; /* group */ | |
1306 | *bp++ = 0; /* unix mode */ | |
1307 | *bp++ = 0; /* segment size */ | |
1308 | ||
1309 | *bp++ = htonl(pos >> 32); | |
1310 | *bp++ = htonl((u32) pos); | |
1311 | *bp++ = htonl(size >> 32); | |
1312 | *bp++ = htonl((u32) size); | |
1313 | *bp++ = htonl(i_size >> 32); | |
1314 | *bp++ = htonl((u32) i_size); | |
1315 | ||
025db80c | 1316 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1317 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
b9b1f8d5 DH |
1318 | } |
1319 | ||
31143d5d DH |
1320 | /* |
1321 | * store a set of pages | |
1322 | */ | |
4343d008 | 1323 | int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, |
31143d5d | 1324 | pgoff_t first, pgoff_t last, |
d2ddc776 | 1325 | unsigned offset, unsigned to) |
31143d5d | 1326 | { |
4343d008 | 1327 | struct afs_vnode *vnode = fc->vnode; |
31143d5d | 1328 | struct afs_call *call; |
f044c884 | 1329 | struct afs_net *net = afs_v2net(vnode); |
31143d5d DH |
1330 | loff_t size, pos, i_size; |
1331 | __be32 *bp; | |
1332 | ||
1333 | _enter(",%x,{%x:%u},,", | |
4343d008 | 1334 | key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); |
31143d5d | 1335 | |
146a1192 | 1336 | size = (loff_t)to - (loff_t)offset; |
31143d5d DH |
1337 | if (first != last) |
1338 | size += (loff_t)(last - first) << PAGE_SHIFT; | |
1339 | pos = (loff_t)first << PAGE_SHIFT; | |
1340 | pos += offset; | |
1341 | ||
1342 | i_size = i_size_read(&vnode->vfs_inode); | |
1343 | if (pos + size > i_size) | |
1344 | i_size = size + pos; | |
1345 | ||
1346 | _debug("size %llx, at %llx, i_size %llx", | |
1347 | (unsigned long long) size, (unsigned long long) pos, | |
1348 | (unsigned long long) i_size); | |
1349 | ||
b9b1f8d5 | 1350 | if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) |
4343d008 | 1351 | return afs_fs_store_data64(fc, mapping, first, last, offset, to, |
d2ddc776 | 1352 | size, pos, i_size); |
31143d5d | 1353 | |
f044c884 | 1354 | call = afs_alloc_flat_call(net, &afs_RXFSStoreData, |
31143d5d DH |
1355 | (4 + 6 + 3) * 4, |
1356 | (21 + 6) * 4); | |
1357 | if (!call) | |
1358 | return -ENOMEM; | |
1359 | ||
4343d008 DH |
1360 | call->key = fc->key; |
1361 | call->mapping = mapping; | |
97e3043a | 1362 | call->reply[0] = vnode; |
31143d5d DH |
1363 | call->first = first; |
1364 | call->last = last; | |
1365 | call->first_offset = offset; | |
1366 | call->last_to = to; | |
1367 | call->send_pages = true; | |
0c3a5ac2 | 1368 | call->expected_version = vnode->status.data_version + 1; |
31143d5d DH |
1369 | |
1370 | /* marshall the parameters */ | |
1371 | bp = call->request; | |
1372 | *bp++ = htonl(FSSTOREDATA); | |
1373 | *bp++ = htonl(vnode->fid.vid); | |
1374 | *bp++ = htonl(vnode->fid.vnode); | |
1375 | *bp++ = htonl(vnode->fid.unique); | |
1376 | ||
ab94f5d0 MD |
1377 | *bp++ = htonl(AFS_SET_MTIME); /* mask */ |
1378 | *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ | |
31143d5d DH |
1379 | *bp++ = 0; /* owner */ |
1380 | *bp++ = 0; /* group */ | |
1381 | *bp++ = 0; /* unix mode */ | |
1382 | *bp++ = 0; /* segment size */ | |
1383 | ||
1384 | *bp++ = htonl(pos); | |
1385 | *bp++ = htonl(size); | |
1386 | *bp++ = htonl(i_size); | |
1387 | ||
d2ddc776 | 1388 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1389 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1390 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
31143d5d DH |
1391 | } |
1392 | ||
1393 | /* | |
1394 | * deliver reply data to an FS.StoreStatus | |
1395 | */ | |
d001648e | 1396 | static int afs_deliver_fs_store_status(struct afs_call *call) |
31143d5d | 1397 | { |
97e3043a | 1398 | struct afs_vnode *vnode = call->reply[0]; |
31143d5d | 1399 | const __be32 *bp; |
372ee163 | 1400 | int ret; |
31143d5d | 1401 | |
d001648e | 1402 | _enter(""); |
31143d5d | 1403 | |
d001648e | 1404 | ret = afs_transfer_reply(call); |
372ee163 DH |
1405 | if (ret < 0) |
1406 | return ret; | |
31143d5d DH |
1407 | |
1408 | /* unmarshall the reply once we've received all of it */ | |
31143d5d | 1409 | bp = call->buffer; |
c875c76a DH |
1410 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
1411 | &call->expected_version, NULL) < 0) | |
5f702c8e | 1412 | return afs_protocol_error(call, -EBADMSG); |
97e3043a | 1413 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
31143d5d DH |
1414 | |
1415 | _leave(" = 0 [done]"); | |
1416 | return 0; | |
1417 | } | |
1418 | ||
1419 | /* | |
1420 | * FS.StoreStatus operation type | |
1421 | */ | |
1422 | static const struct afs_call_type afs_RXFSStoreStatus = { | |
1423 | .name = "FS.StoreStatus", | |
025db80c | 1424 | .op = afs_FS_StoreStatus, |
31143d5d | 1425 | .deliver = afs_deliver_fs_store_status, |
31143d5d DH |
1426 | .destructor = afs_flat_call_destructor, |
1427 | }; | |
1428 | ||
1429 | static const struct afs_call_type afs_RXFSStoreData_as_Status = { | |
1430 | .name = "FS.StoreData", | |
025db80c | 1431 | .op = afs_FS_StoreData, |
31143d5d | 1432 | .deliver = afs_deliver_fs_store_status, |
31143d5d DH |
1433 | .destructor = afs_flat_call_destructor, |
1434 | }; | |
1435 | ||
b9b1f8d5 DH |
1436 | static const struct afs_call_type afs_RXFSStoreData64_as_Status = { |
1437 | .name = "FS.StoreData64", | |
025db80c | 1438 | .op = afs_FS_StoreData64, |
b9b1f8d5 | 1439 | .deliver = afs_deliver_fs_store_status, |
b9b1f8d5 DH |
1440 | .destructor = afs_flat_call_destructor, |
1441 | }; | |
1442 | ||
1443 | /* | |
1444 | * set the attributes on a very large file, using FS.StoreData rather than | |
1445 | * FS.StoreStatus so as to alter the file size also | |
1446 | */ | |
d2ddc776 | 1447 | static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr) |
b9b1f8d5 | 1448 | { |
d2ddc776 | 1449 | struct afs_vnode *vnode = fc->vnode; |
b9b1f8d5 | 1450 | struct afs_call *call; |
f044c884 | 1451 | struct afs_net *net = afs_v2net(vnode); |
b9b1f8d5 DH |
1452 | __be32 *bp; |
1453 | ||
1454 | _enter(",%x,{%x:%u},,", | |
d2ddc776 | 1455 | key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); |
b9b1f8d5 DH |
1456 | |
1457 | ASSERT(attr->ia_valid & ATTR_SIZE); | |
1458 | ||
f044c884 | 1459 | call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status, |
b9b1f8d5 DH |
1460 | (4 + 6 + 3 * 2) * 4, |
1461 | (21 + 6) * 4); | |
1462 | if (!call) | |
1463 | return -ENOMEM; | |
1464 | ||
d2ddc776 | 1465 | call->key = fc->key; |
97e3043a | 1466 | call->reply[0] = vnode; |
0c3a5ac2 | 1467 | call->expected_version = vnode->status.data_version + 1; |
b9b1f8d5 DH |
1468 | |
1469 | /* marshall the parameters */ | |
1470 | bp = call->request; | |
1471 | *bp++ = htonl(FSSTOREDATA64); | |
1472 | *bp++ = htonl(vnode->fid.vid); | |
1473 | *bp++ = htonl(vnode->fid.vnode); | |
1474 | *bp++ = htonl(vnode->fid.unique); | |
1475 | ||
1476 | xdr_encode_AFS_StoreStatus(&bp, attr); | |
1477 | ||
1478 | *bp++ = 0; /* position of start of write */ | |
1479 | *bp++ = 0; | |
1480 | *bp++ = 0; /* size of write */ | |
1481 | *bp++ = 0; | |
1482 | *bp++ = htonl(attr->ia_size >> 32); /* new file length */ | |
1483 | *bp++ = htonl((u32) attr->ia_size); | |
1484 | ||
d2ddc776 | 1485 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1486 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1487 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
b9b1f8d5 DH |
1488 | } |
1489 | ||
31143d5d DH |
1490 | /* |
1491 | * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus | |
1492 | * so as to alter the file size also | |
1493 | */ | |
d2ddc776 | 1494 | static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) |
31143d5d | 1495 | { |
d2ddc776 | 1496 | struct afs_vnode *vnode = fc->vnode; |
31143d5d | 1497 | struct afs_call *call; |
f044c884 | 1498 | struct afs_net *net = afs_v2net(vnode); |
31143d5d DH |
1499 | __be32 *bp; |
1500 | ||
1501 | _enter(",%x,{%x:%u},,", | |
d2ddc776 | 1502 | key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); |
31143d5d DH |
1503 | |
1504 | ASSERT(attr->ia_valid & ATTR_SIZE); | |
b9b1f8d5 | 1505 | if (attr->ia_size >> 32) |
d2ddc776 | 1506 | return afs_fs_setattr_size64(fc, attr); |
31143d5d | 1507 | |
f044c884 | 1508 | call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status, |
31143d5d DH |
1509 | (4 + 6 + 3) * 4, |
1510 | (21 + 6) * 4); | |
1511 | if (!call) | |
1512 | return -ENOMEM; | |
1513 | ||
d2ddc776 | 1514 | call->key = fc->key; |
97e3043a | 1515 | call->reply[0] = vnode; |
0c3a5ac2 | 1516 | call->expected_version = vnode->status.data_version + 1; |
31143d5d DH |
1517 | |
1518 | /* marshall the parameters */ | |
1519 | bp = call->request; | |
1520 | *bp++ = htonl(FSSTOREDATA); | |
1521 | *bp++ = htonl(vnode->fid.vid); | |
1522 | *bp++ = htonl(vnode->fid.vnode); | |
1523 | *bp++ = htonl(vnode->fid.unique); | |
1524 | ||
1525 | xdr_encode_AFS_StoreStatus(&bp, attr); | |
1526 | ||
1527 | *bp++ = 0; /* position of start of write */ | |
1528 | *bp++ = 0; /* size of write */ | |
1529 | *bp++ = htonl(attr->ia_size); /* new file length */ | |
1530 | ||
d2ddc776 | 1531 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1532 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1533 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
31143d5d DH |
1534 | } |
1535 | ||
1536 | /* | |
1537 | * set the attributes on a file, using FS.StoreData if there's a change in file | |
1538 | * size, and FS.StoreStatus otherwise | |
1539 | */ | |
d2ddc776 | 1540 | int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) |
31143d5d | 1541 | { |
d2ddc776 | 1542 | struct afs_vnode *vnode = fc->vnode; |
31143d5d | 1543 | struct afs_call *call; |
f044c884 | 1544 | struct afs_net *net = afs_v2net(vnode); |
31143d5d DH |
1545 | __be32 *bp; |
1546 | ||
1547 | if (attr->ia_valid & ATTR_SIZE) | |
d2ddc776 | 1548 | return afs_fs_setattr_size(fc, attr); |
31143d5d DH |
1549 | |
1550 | _enter(",%x,{%x:%u},,", | |
d2ddc776 | 1551 | key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); |
31143d5d | 1552 | |
f044c884 | 1553 | call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus, |
31143d5d DH |
1554 | (4 + 6) * 4, |
1555 | (21 + 6) * 4); | |
1556 | if (!call) | |
1557 | return -ENOMEM; | |
1558 | ||
d2ddc776 | 1559 | call->key = fc->key; |
97e3043a | 1560 | call->reply[0] = vnode; |
0c3a5ac2 | 1561 | call->expected_version = vnode->status.data_version; |
31143d5d DH |
1562 | |
1563 | /* marshall the parameters */ | |
1564 | bp = call->request; | |
1565 | *bp++ = htonl(FSSTORESTATUS); | |
1566 | *bp++ = htonl(vnode->fid.vid); | |
1567 | *bp++ = htonl(vnode->fid.vnode); | |
1568 | *bp++ = htonl(vnode->fid.unique); | |
1569 | ||
1570 | xdr_encode_AFS_StoreStatus(&bp, attr); | |
1571 | ||
d2ddc776 | 1572 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1573 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1574 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
31143d5d | 1575 | } |
45222b9e DH |
1576 | |
1577 | /* | |
1578 | * deliver reply data to an FS.GetVolumeStatus | |
1579 | */ | |
d001648e | 1580 | static int afs_deliver_fs_get_volume_status(struct afs_call *call) |
45222b9e DH |
1581 | { |
1582 | const __be32 *bp; | |
1583 | char *p; | |
1584 | int ret; | |
1585 | ||
d001648e | 1586 | _enter("{%u}", call->unmarshall); |
45222b9e DH |
1587 | |
1588 | switch (call->unmarshall) { | |
1589 | case 0: | |
1590 | call->offset = 0; | |
1591 | call->unmarshall++; | |
1592 | ||
1593 | /* extract the returned status record */ | |
1594 | case 1: | |
1595 | _debug("extract status"); | |
d001648e DH |
1596 | ret = afs_extract_data(call, call->buffer, |
1597 | 12 * 4, true); | |
372ee163 DH |
1598 | if (ret < 0) |
1599 | return ret; | |
45222b9e DH |
1600 | |
1601 | bp = call->buffer; | |
97e3043a | 1602 | xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]); |
45222b9e DH |
1603 | call->offset = 0; |
1604 | call->unmarshall++; | |
1605 | ||
1606 | /* extract the volume name length */ | |
1607 | case 2: | |
d001648e | 1608 | ret = afs_extract_data(call, &call->tmp, 4, true); |
372ee163 DH |
1609 | if (ret < 0) |
1610 | return ret; | |
45222b9e DH |
1611 | |
1612 | call->count = ntohl(call->tmp); | |
1613 | _debug("volname length: %u", call->count); | |
1614 | if (call->count >= AFSNAMEMAX) | |
5f702c8e | 1615 | return afs_protocol_error(call, -EBADMSG); |
45222b9e DH |
1616 | call->offset = 0; |
1617 | call->unmarshall++; | |
1618 | ||
1619 | /* extract the volume name */ | |
1620 | case 3: | |
1621 | _debug("extract volname"); | |
1622 | if (call->count > 0) { | |
97e3043a | 1623 | ret = afs_extract_data(call, call->reply[2], |
d001648e | 1624 | call->count, true); |
372ee163 DH |
1625 | if (ret < 0) |
1626 | return ret; | |
45222b9e DH |
1627 | } |
1628 | ||
97e3043a | 1629 | p = call->reply[2]; |
45222b9e DH |
1630 | p[call->count] = 0; |
1631 | _debug("volname '%s'", p); | |
1632 | ||
1633 | call->offset = 0; | |
1634 | call->unmarshall++; | |
1635 | ||
1636 | /* extract the volume name padding */ | |
1637 | if ((call->count & 3) == 0) { | |
1638 | call->unmarshall++; | |
1639 | goto no_volname_padding; | |
1640 | } | |
1641 | call->count = 4 - (call->count & 3); | |
1642 | ||
1643 | case 4: | |
d001648e DH |
1644 | ret = afs_extract_data(call, call->buffer, |
1645 | call->count, true); | |
372ee163 DH |
1646 | if (ret < 0) |
1647 | return ret; | |
45222b9e DH |
1648 | |
1649 | call->offset = 0; | |
1650 | call->unmarshall++; | |
1651 | no_volname_padding: | |
1652 | ||
1653 | /* extract the offline message length */ | |
1654 | case 5: | |
d001648e | 1655 | ret = afs_extract_data(call, &call->tmp, 4, true); |
372ee163 DH |
1656 | if (ret < 0) |
1657 | return ret; | |
45222b9e DH |
1658 | |
1659 | call->count = ntohl(call->tmp); | |
1660 | _debug("offline msg length: %u", call->count); | |
1661 | if (call->count >= AFSNAMEMAX) | |
5f702c8e | 1662 | return afs_protocol_error(call, -EBADMSG); |
45222b9e DH |
1663 | call->offset = 0; |
1664 | call->unmarshall++; | |
1665 | ||
1666 | /* extract the offline message */ | |
1667 | case 6: | |
1668 | _debug("extract offline"); | |
1669 | if (call->count > 0) { | |
97e3043a | 1670 | ret = afs_extract_data(call, call->reply[2], |
d001648e | 1671 | call->count, true); |
372ee163 DH |
1672 | if (ret < 0) |
1673 | return ret; | |
45222b9e DH |
1674 | } |
1675 | ||
97e3043a | 1676 | p = call->reply[2]; |
45222b9e DH |
1677 | p[call->count] = 0; |
1678 | _debug("offline '%s'", p); | |
1679 | ||
1680 | call->offset = 0; | |
1681 | call->unmarshall++; | |
1682 | ||
1683 | /* extract the offline message padding */ | |
1684 | if ((call->count & 3) == 0) { | |
1685 | call->unmarshall++; | |
1686 | goto no_offline_padding; | |
1687 | } | |
1688 | call->count = 4 - (call->count & 3); | |
1689 | ||
1690 | case 7: | |
d001648e DH |
1691 | ret = afs_extract_data(call, call->buffer, |
1692 | call->count, true); | |
372ee163 DH |
1693 | if (ret < 0) |
1694 | return ret; | |
45222b9e DH |
1695 | |
1696 | call->offset = 0; | |
1697 | call->unmarshall++; | |
1698 | no_offline_padding: | |
1699 | ||
1700 | /* extract the message of the day length */ | |
1701 | case 8: | |
d001648e | 1702 | ret = afs_extract_data(call, &call->tmp, 4, true); |
372ee163 DH |
1703 | if (ret < 0) |
1704 | return ret; | |
45222b9e DH |
1705 | |
1706 | call->count = ntohl(call->tmp); | |
1707 | _debug("motd length: %u", call->count); | |
1708 | if (call->count >= AFSNAMEMAX) | |
5f702c8e | 1709 | return afs_protocol_error(call, -EBADMSG); |
45222b9e DH |
1710 | call->offset = 0; |
1711 | call->unmarshall++; | |
1712 | ||
1713 | /* extract the message of the day */ | |
1714 | case 9: | |
1715 | _debug("extract motd"); | |
1716 | if (call->count > 0) { | |
97e3043a | 1717 | ret = afs_extract_data(call, call->reply[2], |
d001648e | 1718 | call->count, true); |
372ee163 DH |
1719 | if (ret < 0) |
1720 | return ret; | |
45222b9e DH |
1721 | } |
1722 | ||
97e3043a | 1723 | p = call->reply[2]; |
45222b9e DH |
1724 | p[call->count] = 0; |
1725 | _debug("motd '%s'", p); | |
1726 | ||
1727 | call->offset = 0; | |
1728 | call->unmarshall++; | |
1729 | ||
1730 | /* extract the message of the day padding */ | |
d001648e | 1731 | call->count = (4 - (call->count & 3)) & 3; |
45222b9e DH |
1732 | |
1733 | case 10: | |
d001648e DH |
1734 | ret = afs_extract_data(call, call->buffer, |
1735 | call->count, false); | |
372ee163 DH |
1736 | if (ret < 0) |
1737 | return ret; | |
45222b9e DH |
1738 | |
1739 | call->offset = 0; | |
1740 | call->unmarshall++; | |
45222b9e | 1741 | case 11: |
45222b9e DH |
1742 | break; |
1743 | } | |
1744 | ||
45222b9e DH |
1745 | _leave(" = 0 [done]"); |
1746 | return 0; | |
1747 | } | |
1748 | ||
1749 | /* | |
1750 | * destroy an FS.GetVolumeStatus call | |
1751 | */ | |
1752 | static void afs_get_volume_status_call_destructor(struct afs_call *call) | |
1753 | { | |
97e3043a DH |
1754 | kfree(call->reply[2]); |
1755 | call->reply[2] = NULL; | |
45222b9e DH |
1756 | afs_flat_call_destructor(call); |
1757 | } | |
1758 | ||
1759 | /* | |
1760 | * FS.GetVolumeStatus operation type | |
1761 | */ | |
1762 | static const struct afs_call_type afs_RXFSGetVolumeStatus = { | |
1763 | .name = "FS.GetVolumeStatus", | |
025db80c | 1764 | .op = afs_FS_GetVolumeStatus, |
45222b9e | 1765 | .deliver = afs_deliver_fs_get_volume_status, |
45222b9e DH |
1766 | .destructor = afs_get_volume_status_call_destructor, |
1767 | }; | |
1768 | ||
1769 | /* | |
1770 | * fetch the status of a volume | |
1771 | */ | |
8b2a464c | 1772 | int afs_fs_get_volume_status(struct afs_fs_cursor *fc, |
d2ddc776 | 1773 | struct afs_volume_status *vs) |
45222b9e | 1774 | { |
d2ddc776 | 1775 | struct afs_vnode *vnode = fc->vnode; |
45222b9e | 1776 | struct afs_call *call; |
f044c884 | 1777 | struct afs_net *net = afs_v2net(vnode); |
45222b9e DH |
1778 | __be32 *bp; |
1779 | void *tmpbuf; | |
1780 | ||
1781 | _enter(""); | |
1782 | ||
1783 | tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); | |
1784 | if (!tmpbuf) | |
1785 | return -ENOMEM; | |
1786 | ||
f044c884 | 1787 | call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); |
45222b9e DH |
1788 | if (!call) { |
1789 | kfree(tmpbuf); | |
1790 | return -ENOMEM; | |
1791 | } | |
1792 | ||
d2ddc776 | 1793 | call->key = fc->key; |
97e3043a DH |
1794 | call->reply[0] = vnode; |
1795 | call->reply[1] = vs; | |
1796 | call->reply[2] = tmpbuf; | |
45222b9e DH |
1797 | |
1798 | /* marshall the parameters */ | |
1799 | bp = call->request; | |
1800 | bp[0] = htonl(FSGETVOLUMESTATUS); | |
1801 | bp[1] = htonl(vnode->fid.vid); | |
1802 | ||
d2ddc776 | 1803 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1804 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1805 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
45222b9e | 1806 | } |
e8d6c554 DH |
1807 | |
1808 | /* | |
1809 | * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock | |
1810 | */ | |
d001648e | 1811 | static int afs_deliver_fs_xxxx_lock(struct afs_call *call) |
e8d6c554 DH |
1812 | { |
1813 | const __be32 *bp; | |
372ee163 | 1814 | int ret; |
e8d6c554 | 1815 | |
d001648e | 1816 | _enter("{%u}", call->unmarshall); |
e8d6c554 | 1817 | |
d001648e | 1818 | ret = afs_transfer_reply(call); |
372ee163 DH |
1819 | if (ret < 0) |
1820 | return ret; | |
e8d6c554 DH |
1821 | |
1822 | /* unmarshall the reply once we've received all of it */ | |
1823 | bp = call->buffer; | |
97e3043a | 1824 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
e8d6c554 DH |
1825 | |
1826 | _leave(" = 0 [done]"); | |
1827 | return 0; | |
1828 | } | |
1829 | ||
1830 | /* | |
1831 | * FS.SetLock operation type | |
1832 | */ | |
1833 | static const struct afs_call_type afs_RXFSSetLock = { | |
1834 | .name = "FS.SetLock", | |
025db80c | 1835 | .op = afs_FS_SetLock, |
e8d6c554 | 1836 | .deliver = afs_deliver_fs_xxxx_lock, |
e8d6c554 DH |
1837 | .destructor = afs_flat_call_destructor, |
1838 | }; | |
1839 | ||
1840 | /* | |
1841 | * FS.ExtendLock operation type | |
1842 | */ | |
1843 | static const struct afs_call_type afs_RXFSExtendLock = { | |
1844 | .name = "FS.ExtendLock", | |
025db80c | 1845 | .op = afs_FS_ExtendLock, |
e8d6c554 | 1846 | .deliver = afs_deliver_fs_xxxx_lock, |
e8d6c554 DH |
1847 | .destructor = afs_flat_call_destructor, |
1848 | }; | |
1849 | ||
1850 | /* | |
1851 | * FS.ReleaseLock operation type | |
1852 | */ | |
1853 | static const struct afs_call_type afs_RXFSReleaseLock = { | |
1854 | .name = "FS.ReleaseLock", | |
025db80c | 1855 | .op = afs_FS_ReleaseLock, |
e8d6c554 | 1856 | .deliver = afs_deliver_fs_xxxx_lock, |
e8d6c554 DH |
1857 | .destructor = afs_flat_call_destructor, |
1858 | }; | |
1859 | ||
1860 | /* | |
d2ddc776 | 1861 | * Set a lock on a file |
e8d6c554 | 1862 | */ |
d2ddc776 | 1863 | int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) |
e8d6c554 | 1864 | { |
d2ddc776 | 1865 | struct afs_vnode *vnode = fc->vnode; |
e8d6c554 | 1866 | struct afs_call *call; |
f044c884 | 1867 | struct afs_net *net = afs_v2net(vnode); |
e8d6c554 DH |
1868 | __be32 *bp; |
1869 | ||
1870 | _enter(""); | |
1871 | ||
f044c884 | 1872 | call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4); |
e8d6c554 DH |
1873 | if (!call) |
1874 | return -ENOMEM; | |
1875 | ||
d2ddc776 | 1876 | call->key = fc->key; |
97e3043a | 1877 | call->reply[0] = vnode; |
e8d6c554 DH |
1878 | |
1879 | /* marshall the parameters */ | |
1880 | bp = call->request; | |
1881 | *bp++ = htonl(FSSETLOCK); | |
1882 | *bp++ = htonl(vnode->fid.vid); | |
1883 | *bp++ = htonl(vnode->fid.vnode); | |
1884 | *bp++ = htonl(vnode->fid.unique); | |
1885 | *bp++ = htonl(type); | |
1886 | ||
d2ddc776 | 1887 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1888 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1889 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
e8d6c554 DH |
1890 | } |
1891 | ||
1892 | /* | |
1893 | * extend a lock on a file | |
1894 | */ | |
d2ddc776 | 1895 | int afs_fs_extend_lock(struct afs_fs_cursor *fc) |
e8d6c554 | 1896 | { |
d2ddc776 | 1897 | struct afs_vnode *vnode = fc->vnode; |
e8d6c554 | 1898 | struct afs_call *call; |
f044c884 | 1899 | struct afs_net *net = afs_v2net(vnode); |
e8d6c554 DH |
1900 | __be32 *bp; |
1901 | ||
1902 | _enter(""); | |
1903 | ||
f044c884 | 1904 | call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4); |
e8d6c554 DH |
1905 | if (!call) |
1906 | return -ENOMEM; | |
1907 | ||
d2ddc776 | 1908 | call->key = fc->key; |
97e3043a | 1909 | call->reply[0] = vnode; |
e8d6c554 DH |
1910 | |
1911 | /* marshall the parameters */ | |
1912 | bp = call->request; | |
1913 | *bp++ = htonl(FSEXTENDLOCK); | |
1914 | *bp++ = htonl(vnode->fid.vid); | |
1915 | *bp++ = htonl(vnode->fid.vnode); | |
1916 | *bp++ = htonl(vnode->fid.unique); | |
1917 | ||
d2ddc776 | 1918 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1919 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1920 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
e8d6c554 DH |
1921 | } |
1922 | ||
1923 | /* | |
1924 | * release a lock on a file | |
1925 | */ | |
d2ddc776 | 1926 | int afs_fs_release_lock(struct afs_fs_cursor *fc) |
e8d6c554 | 1927 | { |
d2ddc776 | 1928 | struct afs_vnode *vnode = fc->vnode; |
e8d6c554 | 1929 | struct afs_call *call; |
f044c884 | 1930 | struct afs_net *net = afs_v2net(vnode); |
e8d6c554 DH |
1931 | __be32 *bp; |
1932 | ||
1933 | _enter(""); | |
1934 | ||
f044c884 | 1935 | call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4); |
e8d6c554 DH |
1936 | if (!call) |
1937 | return -ENOMEM; | |
1938 | ||
d2ddc776 | 1939 | call->key = fc->key; |
97e3043a | 1940 | call->reply[0] = vnode; |
e8d6c554 DH |
1941 | |
1942 | /* marshall the parameters */ | |
1943 | bp = call->request; | |
1944 | *bp++ = htonl(FSRELEASELOCK); | |
1945 | *bp++ = htonl(vnode->fid.vid); | |
1946 | *bp++ = htonl(vnode->fid.vnode); | |
1947 | *bp++ = htonl(vnode->fid.unique); | |
1948 | ||
d2ddc776 | 1949 | afs_use_fs_server(call, fc->cbi); |
025db80c | 1950 | trace_afs_make_fs_call(call, &vnode->fid); |
d2ddc776 | 1951 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); |
c435ee34 DH |
1952 | } |
1953 | ||
1954 | /* | |
1955 | * Deliver reply data to an FS.GiveUpAllCallBacks operation. | |
1956 | */ | |
1957 | static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call) | |
1958 | { | |
1959 | return afs_transfer_reply(call); | |
1960 | } | |
1961 | ||
1962 | /* | |
1963 | * FS.GiveUpAllCallBacks operation type | |
1964 | */ | |
1965 | static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = { | |
1966 | .name = "FS.GiveUpAllCallBacks", | |
025db80c | 1967 | .op = afs_FS_GiveUpAllCallBacks, |
c435ee34 DH |
1968 | .deliver = afs_deliver_fs_give_up_all_callbacks, |
1969 | .destructor = afs_flat_call_destructor, | |
1970 | }; | |
1971 | ||
1972 | /* | |
1973 | * Flush all the callbacks we have on a server. | |
1974 | */ | |
d2ddc776 DH |
1975 | int afs_fs_give_up_all_callbacks(struct afs_net *net, |
1976 | struct afs_server *server, | |
8b2a464c | 1977 | struct afs_addr_cursor *ac, |
d2ddc776 | 1978 | struct key *key) |
c435ee34 DH |
1979 | { |
1980 | struct afs_call *call; | |
1981 | __be32 *bp; | |
1982 | ||
1983 | _enter(""); | |
1984 | ||
d2ddc776 | 1985 | call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0); |
c435ee34 DH |
1986 | if (!call) |
1987 | return -ENOMEM; | |
1988 | ||
1989 | call->key = key; | |
1990 | ||
1991 | /* marshall the parameters */ | |
1992 | bp = call->request; | |
1993 | *bp++ = htonl(FSGIVEUPALLCALLBACKS); | |
1994 | ||
1995 | /* Can't take a ref on server */ | |
d2ddc776 DH |
1996 | return afs_make_call(ac, call, GFP_NOFS, false); |
1997 | } | |
1998 | ||
1999 | /* | |
2000 | * Deliver reply data to an FS.GetCapabilities operation. | |
2001 | */ | |
2002 | static int afs_deliver_fs_get_capabilities(struct afs_call *call) | |
2003 | { | |
2004 | u32 count; | |
2005 | int ret; | |
2006 | ||
2007 | _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count); | |
2008 | ||
2009 | again: | |
2010 | switch (call->unmarshall) { | |
2011 | case 0: | |
2012 | call->offset = 0; | |
2013 | call->unmarshall++; | |
2014 | ||
2015 | /* Extract the capabilities word count */ | |
2016 | case 1: | |
2017 | ret = afs_extract_data(call, &call->tmp, | |
2018 | 1 * sizeof(__be32), | |
2019 | true); | |
2020 | if (ret < 0) | |
2021 | return ret; | |
2022 | ||
2023 | count = ntohl(call->tmp); | |
2024 | ||
2025 | call->count = count; | |
2026 | call->count2 = count; | |
2027 | call->offset = 0; | |
2028 | call->unmarshall++; | |
2029 | ||
2030 | /* Extract capabilities words */ | |
2031 | case 2: | |
2032 | count = min(call->count, 16U); | |
2033 | ret = afs_extract_data(call, call->buffer, | |
2034 | count * sizeof(__be32), | |
2035 | call->count > 16); | |
2036 | if (ret < 0) | |
2037 | return ret; | |
2038 | ||
2039 | /* TODO: Examine capabilities */ | |
2040 | ||
2041 | call->count -= count; | |
2042 | if (call->count > 0) | |
2043 | goto again; | |
2044 | call->offset = 0; | |
2045 | call->unmarshall++; | |
2046 | break; | |
2047 | } | |
2048 | ||
2049 | _leave(" = 0 [done]"); | |
2050 | return 0; | |
2051 | } | |
2052 | ||
2053 | /* | |
2054 | * FS.GetCapabilities operation type | |
2055 | */ | |
2056 | static const struct afs_call_type afs_RXFSGetCapabilities = { | |
2057 | .name = "FS.GetCapabilities", | |
025db80c | 2058 | .op = afs_FS_GetCapabilities, |
d2ddc776 DH |
2059 | .deliver = afs_deliver_fs_get_capabilities, |
2060 | .destructor = afs_flat_call_destructor, | |
2061 | }; | |
2062 | ||
2063 | /* | |
2064 | * Probe a fileserver for the capabilities that it supports. This can | |
2065 | * return up to 196 words. | |
2066 | */ | |
2067 | int afs_fs_get_capabilities(struct afs_net *net, | |
2068 | struct afs_server *server, | |
2069 | struct afs_addr_cursor *ac, | |
2070 | struct key *key) | |
2071 | { | |
2072 | struct afs_call *call; | |
2073 | __be32 *bp; | |
2074 | ||
2075 | _enter(""); | |
2076 | ||
2077 | call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4); | |
2078 | if (!call) | |
2079 | return -ENOMEM; | |
2080 | ||
2081 | call->key = key; | |
2082 | ||
2083 | /* marshall the parameters */ | |
2084 | bp = call->request; | |
2085 | *bp++ = htonl(FSGETCAPABILITIES); | |
2086 | ||
2087 | /* Can't take a ref on server */ | |
025db80c | 2088 | trace_afs_make_fs_call(call, NULL); |
d2ddc776 | 2089 | return afs_make_call(ac, call, GFP_NOFS, false); |
e8d6c554 | 2090 | } |
5cf9dd55 DH |
2091 | |
2092 | /* | |
2093 | * Deliver reply data to an FS.FetchStatus with no vnode. | |
2094 | */ | |
2095 | static int afs_deliver_fs_fetch_status(struct afs_call *call) | |
2096 | { | |
2097 | struct afs_file_status *status = call->reply[1]; | |
2098 | struct afs_callback *callback = call->reply[2]; | |
2099 | struct afs_volsync *volsync = call->reply[3]; | |
2100 | struct afs_vnode *vnode = call->reply[0]; | |
2101 | const __be32 *bp; | |
2102 | int ret; | |
2103 | ||
2104 | ret = afs_transfer_reply(call); | |
2105 | if (ret < 0) | |
2106 | return ret; | |
2107 | ||
2108 | _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); | |
2109 | ||
2110 | /* unmarshall the reply once we've received all of it */ | |
2111 | bp = call->buffer; | |
c875c76a DH |
2112 | afs_decode_status(call, &bp, status, vnode, |
2113 | &call->expected_version, NULL); | |
5cf9dd55 DH |
2114 | callback[call->count].version = ntohl(bp[0]); |
2115 | callback[call->count].expiry = ntohl(bp[1]); | |
2116 | callback[call->count].type = ntohl(bp[2]); | |
2117 | if (vnode) | |
2118 | xdr_decode_AFSCallBack(call, vnode, &bp); | |
2119 | else | |
2120 | bp += 3; | |
2121 | if (volsync) | |
2122 | xdr_decode_AFSVolSync(&bp, volsync); | |
2123 | ||
2124 | _leave(" = 0 [done]"); | |
2125 | return 0; | |
2126 | } | |
2127 | ||
2128 | /* | |
2129 | * FS.FetchStatus operation type | |
2130 | */ | |
2131 | static const struct afs_call_type afs_RXFSFetchStatus = { | |
2132 | .name = "FS.FetchStatus", | |
2133 | .op = afs_FS_FetchStatus, | |
2134 | .deliver = afs_deliver_fs_fetch_status, | |
2135 | .destructor = afs_flat_call_destructor, | |
2136 | }; | |
2137 | ||
2138 | /* | |
2139 | * Fetch the status information for a fid without needing a vnode handle. | |
2140 | */ | |
2141 | int afs_fs_fetch_status(struct afs_fs_cursor *fc, | |
2142 | struct afs_net *net, | |
2143 | struct afs_fid *fid, | |
2144 | struct afs_file_status *status, | |
2145 | struct afs_callback *callback, | |
2146 | struct afs_volsync *volsync) | |
2147 | { | |
2148 | struct afs_call *call; | |
2149 | __be32 *bp; | |
2150 | ||
2151 | _enter(",%x,{%x:%u},,", | |
2152 | key_serial(fc->key), fid->vid, fid->vnode); | |
2153 | ||
2154 | call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); | |
2155 | if (!call) { | |
2156 | fc->ac.error = -ENOMEM; | |
2157 | return -ENOMEM; | |
2158 | } | |
2159 | ||
2160 | call->key = fc->key; | |
2161 | call->reply[0] = NULL; /* vnode for fid[0] */ | |
2162 | call->reply[1] = status; | |
2163 | call->reply[2] = callback; | |
2164 | call->reply[3] = volsync; | |
0c3a5ac2 | 2165 | call->expected_version = 1; /* vnode->status.data_version */ |
5cf9dd55 DH |
2166 | |
2167 | /* marshall the parameters */ | |
2168 | bp = call->request; | |
2169 | bp[0] = htonl(FSFETCHSTATUS); | |
2170 | bp[1] = htonl(fid->vid); | |
2171 | bp[2] = htonl(fid->vnode); | |
2172 | bp[3] = htonl(fid->unique); | |
2173 | ||
2174 | call->cb_break = fc->cb_break; | |
2175 | afs_use_fs_server(call, fc->cbi); | |
2176 | trace_afs_make_fs_call(call, fid); | |
2177 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); | |
2178 | } | |
2179 | ||
2180 | /* | |
2181 | * Deliver reply data to an FS.InlineBulkStatus call | |
2182 | */ | |
2183 | static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) | |
2184 | { | |
2185 | struct afs_file_status *statuses; | |
2186 | struct afs_callback *callbacks; | |
2187 | struct afs_vnode *vnode = call->reply[0]; | |
2188 | const __be32 *bp; | |
2189 | u32 tmp; | |
2190 | int ret; | |
2191 | ||
2192 | _enter("{%u}", call->unmarshall); | |
2193 | ||
2194 | switch (call->unmarshall) { | |
2195 | case 0: | |
2196 | call->offset = 0; | |
2197 | call->unmarshall++; | |
2198 | ||
2199 | /* Extract the file status count and array in two steps */ | |
2200 | case 1: | |
2201 | _debug("extract status count"); | |
2202 | ret = afs_extract_data(call, &call->tmp, 4, true); | |
2203 | if (ret < 0) | |
2204 | return ret; | |
2205 | ||
2206 | tmp = ntohl(call->tmp); | |
2207 | _debug("status count: %u/%u", tmp, call->count2); | |
2208 | if (tmp != call->count2) | |
5f702c8e | 2209 | return afs_protocol_error(call, -EBADMSG); |
5cf9dd55 DH |
2210 | |
2211 | call->count = 0; | |
2212 | call->unmarshall++; | |
2213 | more_counts: | |
2214 | call->offset = 0; | |
2215 | ||
2216 | case 2: | |
2217 | _debug("extract status array %u", call->count); | |
2218 | ret = afs_extract_data(call, call->buffer, 21 * 4, true); | |
2219 | if (ret < 0) | |
2220 | return ret; | |
2221 | ||
2222 | bp = call->buffer; | |
2223 | statuses = call->reply[1]; | |
c875c76a DH |
2224 | if (afs_decode_status(call, &bp, &statuses[call->count], |
2225 | call->count == 0 ? vnode : NULL, | |
2226 | NULL, NULL) < 0) | |
5f702c8e | 2227 | return afs_protocol_error(call, -EBADMSG); |
5cf9dd55 DH |
2228 | |
2229 | call->count++; | |
2230 | if (call->count < call->count2) | |
2231 | goto more_counts; | |
2232 | ||
2233 | call->count = 0; | |
2234 | call->unmarshall++; | |
2235 | call->offset = 0; | |
2236 | ||
2237 | /* Extract the callback count and array in two steps */ | |
2238 | case 3: | |
2239 | _debug("extract CB count"); | |
2240 | ret = afs_extract_data(call, &call->tmp, 4, true); | |
2241 | if (ret < 0) | |
2242 | return ret; | |
2243 | ||
2244 | tmp = ntohl(call->tmp); | |
2245 | _debug("CB count: %u", tmp); | |
2246 | if (tmp != call->count2) | |
5f702c8e | 2247 | return afs_protocol_error(call, -EBADMSG); |
5cf9dd55 DH |
2248 | call->count = 0; |
2249 | call->unmarshall++; | |
2250 | more_cbs: | |
2251 | call->offset = 0; | |
2252 | ||
2253 | case 4: | |
2254 | _debug("extract CB array"); | |
2255 | ret = afs_extract_data(call, call->buffer, 3 * 4, true); | |
2256 | if (ret < 0) | |
2257 | return ret; | |
2258 | ||
2259 | _debug("unmarshall CB array"); | |
2260 | bp = call->buffer; | |
2261 | callbacks = call->reply[2]; | |
2262 | callbacks[call->count].version = ntohl(bp[0]); | |
2263 | callbacks[call->count].expiry = ntohl(bp[1]); | |
2264 | callbacks[call->count].type = ntohl(bp[2]); | |
2265 | statuses = call->reply[1]; | |
2266 | if (call->count == 0 && vnode && statuses[0].abort_code == 0) | |
2267 | xdr_decode_AFSCallBack(call, vnode, &bp); | |
2268 | call->count++; | |
2269 | if (call->count < call->count2) | |
2270 | goto more_cbs; | |
2271 | ||
2272 | call->offset = 0; | |
2273 | call->unmarshall++; | |
2274 | ||
2275 | case 5: | |
2276 | ret = afs_extract_data(call, call->buffer, 6 * 4, false); | |
2277 | if (ret < 0) | |
2278 | return ret; | |
2279 | ||
2280 | bp = call->buffer; | |
2281 | if (call->reply[3]) | |
2282 | xdr_decode_AFSVolSync(&bp, call->reply[3]); | |
2283 | ||
2284 | call->offset = 0; | |
2285 | call->unmarshall++; | |
2286 | ||
2287 | case 6: | |
2288 | break; | |
2289 | } | |
2290 | ||
2291 | _leave(" = 0 [done]"); | |
2292 | return 0; | |
2293 | } | |
2294 | ||
2295 | /* | |
2296 | * FS.InlineBulkStatus operation type | |
2297 | */ | |
2298 | static const struct afs_call_type afs_RXFSInlineBulkStatus = { | |
2299 | .name = "FS.InlineBulkStatus", | |
2300 | .op = afs_FS_InlineBulkStatus, | |
2301 | .deliver = afs_deliver_fs_inline_bulk_status, | |
2302 | .destructor = afs_flat_call_destructor, | |
2303 | }; | |
2304 | ||
2305 | /* | |
2306 | * Fetch the status information for up to 50 files | |
2307 | */ | |
2308 | int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, | |
2309 | struct afs_net *net, | |
2310 | struct afs_fid *fids, | |
2311 | struct afs_file_status *statuses, | |
2312 | struct afs_callback *callbacks, | |
2313 | unsigned int nr_fids, | |
2314 | struct afs_volsync *volsync) | |
2315 | { | |
2316 | struct afs_call *call; | |
2317 | __be32 *bp; | |
2318 | int i; | |
2319 | ||
2320 | _enter(",%x,{%x:%u},%u", | |
2321 | key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids); | |
2322 | ||
2323 | call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus, | |
2324 | (2 + nr_fids * 3) * 4, | |
2325 | 21 * 4); | |
2326 | if (!call) { | |
2327 | fc->ac.error = -ENOMEM; | |
2328 | return -ENOMEM; | |
2329 | } | |
2330 | ||
2331 | call->key = fc->key; | |
2332 | call->reply[0] = NULL; /* vnode for fid[0] */ | |
2333 | call->reply[1] = statuses; | |
2334 | call->reply[2] = callbacks; | |
2335 | call->reply[3] = volsync; | |
2336 | call->count2 = nr_fids; | |
2337 | ||
2338 | /* marshall the parameters */ | |
2339 | bp = call->request; | |
2340 | *bp++ = htonl(FSINLINEBULKSTATUS); | |
2341 | *bp++ = htonl(nr_fids); | |
2342 | for (i = 0; i < nr_fids; i++) { | |
2343 | *bp++ = htonl(fids[i].vid); | |
2344 | *bp++ = htonl(fids[i].vnode); | |
2345 | *bp++ = htonl(fids[i].unique); | |
2346 | } | |
2347 | ||
2348 | call->cb_break = fc->cb_break; | |
2349 | afs_use_fs_server(call, fc->cbi); | |
2350 | trace_afs_make_fs_call(call, &fids[0]); | |
2351 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); | |
2352 | } |