1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* YFS File Server client stubs |
3 | * |
4 | * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | */ |
7 | |
8 | #include <linux/init.h> |
9 | #include <linux/slab.h> |
10 | #include <linux/sched.h> |
11 | #include <linux/circ_buf.h> |
12 | #include <linux/iversion.h> |
13 | #include "internal.h" |
14 | #include "afs_fs.h" |
15 | #include "xdr_fs.h" |
16 | #include "protocol_yfs.h" |
17 | |
18 | #define xdr_size(x) (sizeof(*x) / sizeof(__be32)) |
19 | |
20 | static void xdr_decode_YFSFid(const __be32 **_bp, struct afs_fid *fid) |
21 | { |
22 | const struct yfs_xdr_YFSFid *x = (const void *)*_bp; |
23 | |
24 | fid->vid = xdr_to_u64(x: x->volume); |
25 | fid->vnode = xdr_to_u64(x: x->vnode.lo); |
26 | fid->vnode_hi = ntohl(x->vnode.hi); |
27 | fid->unique = ntohl(x->vnode.unique); |
28 | *_bp += xdr_size(x); |
29 | } |
30 | |
31 | static __be32 *xdr_encode_u32(__be32 *bp, u32 n) |
32 | { |
33 | *bp++ = htonl(n); |
34 | return bp; |
35 | } |
36 | |
37 | static __be32 *xdr_encode_u64(__be32 *bp, u64 n) |
38 | { |
39 | struct yfs_xdr_u64 *x = (void *)bp; |
40 | |
41 | *x = u64_to_xdr(x: n); |
42 | return bp + xdr_size(x); |
43 | } |
44 | |
45 | static __be32 *xdr_encode_YFSFid(__be32 *bp, struct afs_fid *fid) |
46 | { |
47 | struct yfs_xdr_YFSFid *x = (void *)bp; |
48 | |
49 | x->volume = u64_to_xdr(x: fid->vid); |
50 | x->vnode.lo = u64_to_xdr(x: fid->vnode); |
51 | x->vnode.hi = htonl(fid->vnode_hi); |
52 | x->vnode.unique = htonl(fid->unique); |
53 | return bp + xdr_size(x); |
54 | } |
55 | |
56 | static size_t xdr_strlen(unsigned int len) |
57 | { |
58 | return sizeof(__be32) + round_up(len, sizeof(__be32)); |
59 | } |
60 | |
61 | static __be32 *xdr_encode_string(__be32 *bp, const char *p, unsigned int len) |
62 | { |
63 | bp = xdr_encode_u32(bp, n: len); |
64 | bp = memcpy(bp, p, len); |
65 | if (len & 3) { |
66 | unsigned int pad = 4 - (len & 3); |
67 | |
68 | memset((u8 *)bp + len, 0, pad); |
69 | len += pad; |
70 | } |
71 | |
72 | return bp + len / sizeof(__be32); |
73 | } |
74 | |
75 | static __be32 *xdr_encode_name(__be32 *bp, const struct qstr *p) |
76 | { |
77 | return xdr_encode_string(bp, p: p->name, len: p->len); |
78 | } |
79 | |
80 | static s64 linux_to_yfs_time(const struct timespec64 *t) |
81 | { |
82 | /* Convert to 100ns intervals. */ |
83 | return (u64)t->tv_sec * 10000000 + t->tv_nsec/100; |
84 | } |
85 | |
86 | static __be32 *xdr_encode_YFSStoreStatus(__be32 *bp, mode_t *mode, |
87 | const struct timespec64 *t) |
88 | { |
89 | struct yfs_xdr_YFSStoreStatus *x = (void *)bp; |
90 | mode_t masked_mode = mode ? *mode & S_IALLUGO : 0; |
91 | s64 mtime = linux_to_yfs_time(t); |
92 | u32 mask = AFS_SET_MTIME; |
93 | |
94 | mask |= mode ? AFS_SET_MODE : 0; |
95 | |
96 | x->mask = htonl(mask); |
97 | x->mode = htonl(masked_mode); |
98 | x->mtime_client = u64_to_xdr(x: mtime); |
99 | x->owner = u64_to_xdr(x: 0); |
100 | x->group = u64_to_xdr(x: 0); |
101 | return bp + xdr_size(x); |
102 | } |
103 | |
104 | /* |
105 | * Convert a signed 100ns-resolution 64-bit time into a timespec. |
106 | */ |
107 | static struct timespec64 yfs_time_to_linux(s64 t) |
108 | { |
109 | struct timespec64 ts; |
110 | u64 abs_t; |
111 | |
112 | /* |
113 | * Unfortunately can not use normal 64 bit division on 32 bit arch, but |
114 | * the alternative, do_div, does not work with negative numbers so have |
115 | * to special case them |
116 | */ |
117 | if (t < 0) { |
118 | abs_t = -t; |
119 | ts.tv_nsec = (time64_t)(do_div(abs_t, 10000000) * 100); |
120 | ts.tv_nsec = -ts.tv_nsec; |
121 | ts.tv_sec = -abs_t; |
122 | } else { |
123 | abs_t = t; |
124 | ts.tv_nsec = (time64_t)do_div(abs_t, 10000000) * 100; |
125 | ts.tv_sec = abs_t; |
126 | } |
127 | |
128 | return ts; |
129 | } |
130 | |
131 | static struct timespec64 xdr_to_time(const struct yfs_xdr_u64 xdr) |
132 | { |
133 | s64 t = xdr_to_u64(x: xdr); |
134 | |
135 | return yfs_time_to_linux(t); |
136 | } |
137 | |
138 | static void yfs_check_req(struct afs_call *call, __be32 *bp) |
139 | { |
140 | size_t len = (void *)bp - call->request; |
141 | |
142 | if (len > call->request_size) |
143 | pr_err("kAFS: %s: Request buffer overflow (%zu>%u)\n" , |
144 | call->type->name, len, call->request_size); |
145 | else if (len < call->request_size) |
146 | pr_warn("kAFS: %s: Request buffer underflow (%zu<%u)\n" , |
147 | call->type->name, len, call->request_size); |
148 | } |
149 | |
150 | /* |
151 | * Dump a bad file status record. |
152 | */ |
153 | static void xdr_dump_bad(const __be32 *bp) |
154 | { |
155 | __be32 x[4]; |
156 | int i; |
157 | |
158 | pr_notice("YFS XDR: Bad status record\n" ); |
159 | for (i = 0; i < 6 * 4 * 4; i += 16) { |
160 | memcpy(x, bp, 16); |
161 | bp += 4; |
162 | pr_notice("%03x: %08x %08x %08x %08x\n" , |
163 | i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3])); |
164 | } |
165 | |
166 | memcpy(x, bp, 8); |
167 | pr_notice("0x60: %08x %08x\n" , ntohl(x[0]), ntohl(x[1])); |
168 | } |
169 | |
170 | /* |
171 | * Decode a YFSFetchStatus block |
172 | */ |
173 | static void xdr_decode_YFSFetchStatus(const __be32 **_bp, |
174 | struct afs_call *call, |
175 | struct afs_status_cb *scb) |
176 | { |
177 | const struct yfs_xdr_YFSFetchStatus *xdr = (const void *)*_bp; |
178 | struct afs_file_status *status = &scb->status; |
179 | u32 type; |
180 | |
181 | status->abort_code = ntohl(xdr->abort_code); |
182 | if (status->abort_code != 0) { |
183 | if (status->abort_code == VNOVNODE) |
184 | status->nlink = 0; |
185 | scb->have_error = true; |
186 | goto advance; |
187 | } |
188 | |
189 | type = ntohl(xdr->type); |
190 | switch (type) { |
191 | case AFS_FTYPE_FILE: |
192 | case AFS_FTYPE_DIR: |
193 | case AFS_FTYPE_SYMLINK: |
194 | status->type = type; |
195 | break; |
196 | default: |
197 | goto bad; |
198 | } |
199 | |
200 | status->nlink = ntohl(xdr->nlink); |
201 | status->author = xdr_to_u64(x: xdr->author); |
202 | status->owner = xdr_to_u64(x: xdr->owner); |
203 | status->caller_access = ntohl(xdr->caller_access); /* Ticket dependent */ |
204 | status->anon_access = ntohl(xdr->anon_access); |
205 | status->mode = ntohl(xdr->mode) & S_IALLUGO; |
206 | status->group = xdr_to_u64(x: xdr->group); |
207 | status->lock_count = ntohl(xdr->lock_count); |
208 | |
209 | status->mtime_client = xdr_to_time(xdr: xdr->mtime_client); |
210 | status->mtime_server = xdr_to_time(xdr: xdr->mtime_server); |
211 | status->size = xdr_to_u64(x: xdr->size); |
212 | status->data_version = xdr_to_u64(x: xdr->data_version); |
213 | scb->have_status = true; |
214 | advance: |
215 | *_bp += xdr_size(xdr); |
216 | return; |
217 | |
218 | bad: |
219 | xdr_dump_bad(bp: *_bp); |
220 | afs_protocol_error(call, afs_eproto_bad_status); |
221 | goto advance; |
222 | } |
223 | |
224 | /* |
225 | * Decode a YFSCallBack block |
226 | */ |
227 | static void xdr_decode_YFSCallBack(const __be32 **_bp, |
228 | struct afs_call *call, |
229 | struct afs_status_cb *scb) |
230 | { |
231 | struct yfs_xdr_YFSCallBack *x = (void *)*_bp; |
232 | struct afs_callback *cb = &scb->callback; |
233 | ktime_t cb_expiry; |
234 | |
235 | cb_expiry = ktime_add(call->issue_time, xdr_to_u64(x->expiration_time) * 100); |
236 | cb->expires_at = ktime_divns(kt: cb_expiry, NSEC_PER_SEC); |
237 | scb->have_cb = true; |
238 | *_bp += xdr_size(x); |
239 | } |
240 | |
241 | /* |
242 | * Decode a YFSVolSync block |
243 | */ |
244 | static void xdr_decode_YFSVolSync(const __be32 **_bp, |
245 | struct afs_volsync *volsync) |
246 | { |
247 | struct yfs_xdr_YFSVolSync *x = (void *)*_bp; |
248 | u64 creation; |
249 | |
250 | if (volsync) { |
251 | creation = xdr_to_u64(x: x->vol_creation_date); |
252 | do_div(creation, 10 * 1000 * 1000); |
253 | volsync->creation = creation; |
254 | } |
255 | |
256 | *_bp += xdr_size(x); |
257 | } |
258 | |
259 | /* |
260 | * Encode the requested attributes into a YFSStoreStatus block |
261 | */ |
262 | static __be32 *xdr_encode_YFS_StoreStatus(__be32 *bp, struct iattr *attr) |
263 | { |
264 | struct yfs_xdr_YFSStoreStatus *x = (void *)bp; |
265 | s64 mtime = 0, owner = 0, group = 0; |
266 | u32 mask = 0, mode = 0; |
267 | |
268 | mask = 0; |
269 | if (attr->ia_valid & ATTR_MTIME) { |
270 | mask |= AFS_SET_MTIME; |
271 | mtime = linux_to_yfs_time(t: &attr->ia_mtime); |
272 | } |
273 | |
274 | if (attr->ia_valid & ATTR_UID) { |
275 | mask |= AFS_SET_OWNER; |
276 | owner = from_kuid(to: &init_user_ns, uid: attr->ia_uid); |
277 | } |
278 | |
279 | if (attr->ia_valid & ATTR_GID) { |
280 | mask |= AFS_SET_GROUP; |
281 | group = from_kgid(to: &init_user_ns, gid: attr->ia_gid); |
282 | } |
283 | |
284 | if (attr->ia_valid & ATTR_MODE) { |
285 | mask |= AFS_SET_MODE; |
286 | mode = attr->ia_mode & S_IALLUGO; |
287 | } |
288 | |
289 | x->mask = htonl(mask); |
290 | x->mode = htonl(mode); |
291 | x->mtime_client = u64_to_xdr(x: mtime); |
292 | x->owner = u64_to_xdr(x: owner); |
293 | x->group = u64_to_xdr(x: group); |
294 | return bp + xdr_size(x); |
295 | } |
296 | |
297 | /* |
298 | * Decode a YFSFetchVolumeStatus block. |
299 | */ |
300 | static void xdr_decode_YFSFetchVolumeStatus(const __be32 **_bp, |
301 | struct afs_volume_status *vs) |
302 | { |
303 | const struct yfs_xdr_YFSFetchVolumeStatus *x = (const void *)*_bp; |
304 | u32 flags; |
305 | |
306 | vs->vid = xdr_to_u64(x: x->vid); |
307 | vs->parent_id = xdr_to_u64(x: x->parent_id); |
308 | flags = ntohl(x->flags); |
309 | vs->online = flags & yfs_FVSOnline; |
310 | vs->in_service = flags & yfs_FVSInservice; |
311 | vs->blessed = flags & yfs_FVSBlessed; |
312 | vs->needs_salvage = flags & yfs_FVSNeedsSalvage; |
313 | vs->type = ntohl(x->type); |
314 | vs->min_quota = 0; |
315 | vs->max_quota = xdr_to_u64(x: x->max_quota); |
316 | vs->blocks_in_use = xdr_to_u64(x: x->blocks_in_use); |
317 | vs->part_blocks_avail = xdr_to_u64(x: x->part_blocks_avail); |
318 | vs->part_max_blocks = xdr_to_u64(x: x->part_max_blocks); |
319 | vs->vol_copy_date = xdr_to_u64(x: x->vol_copy_date); |
320 | vs->vol_backup_date = xdr_to_u64(x: x->vol_backup_date); |
321 | *_bp += sizeof(*x) / sizeof(__be32); |
322 | } |
323 | |
324 | /* |
325 | * Deliver reply data to operations that just return a file status and a volume |
326 | * sync record. |
327 | */ |
328 | static int yfs_deliver_status_and_volsync(struct afs_call *call) |
329 | { |
330 | struct afs_operation *op = call->op; |
331 | const __be32 *bp; |
332 | int ret; |
333 | |
334 | ret = afs_transfer_reply(call); |
335 | if (ret < 0) |
336 | return ret; |
337 | |
338 | bp = call->buffer; |
339 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &op->file[0].scb); |
340 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
341 | |
342 | _leave(" = 0 [done]" ); |
343 | return 0; |
344 | } |
345 | |
346 | /* |
347 | * Deliver reply data to an YFS.FetchData64. |
348 | */ |
349 | static int yfs_deliver_fs_fetch_data64(struct afs_call *call) |
350 | { |
351 | struct afs_operation *op = call->op; |
352 | struct afs_vnode_param *vp = &op->file[0]; |
353 | struct afs_read *req = op->fetch.req; |
354 | const __be32 *bp; |
355 | int ret; |
356 | |
357 | _enter("{%u,%zu, %zu/%llu}" , |
358 | call->unmarshall, call->iov_len, iov_iter_count(call->iter), |
359 | req->actual_len); |
360 | |
361 | switch (call->unmarshall) { |
362 | case 0: |
363 | req->actual_len = 0; |
364 | afs_extract_to_tmp64(call); |
365 | call->unmarshall++; |
366 | fallthrough; |
367 | |
368 | /* Extract the returned data length into ->actual_len. This |
369 | * may indicate more or less data than was requested will be |
370 | * returned. |
371 | */ |
372 | case 1: |
373 | _debug("extract data length" ); |
374 | ret = afs_extract_data(call, true); |
375 | if (ret < 0) |
376 | return ret; |
377 | |
378 | req->actual_len = be64_to_cpu(call->tmp64); |
379 | _debug("DATA length: %llu" , req->actual_len); |
380 | |
381 | if (req->actual_len == 0) |
382 | goto no_more_data; |
383 | |
384 | call->iter = req->iter; |
385 | call->iov_len = min(req->actual_len, req->len); |
386 | call->unmarshall++; |
387 | fallthrough; |
388 | |
389 | /* extract the returned data */ |
390 | case 2: |
391 | _debug("extract data %zu/%llu" , |
392 | iov_iter_count(call->iter), req->actual_len); |
393 | |
394 | ret = afs_extract_data(call, true); |
395 | if (ret < 0) |
396 | return ret; |
397 | |
398 | call->iter = &call->def_iter; |
399 | if (req->actual_len <= req->len) |
400 | goto no_more_data; |
401 | |
402 | /* Discard any excess data the server gave us */ |
403 | afs_extract_discard(call, size: req->actual_len - req->len); |
404 | call->unmarshall = 3; |
405 | fallthrough; |
406 | |
407 | case 3: |
408 | _debug("extract discard %zu/%llu" , |
409 | iov_iter_count(call->iter), req->actual_len - req->len); |
410 | |
411 | ret = afs_extract_data(call, true); |
412 | if (ret < 0) |
413 | return ret; |
414 | |
415 | no_more_data: |
416 | call->unmarshall = 4; |
417 | afs_extract_to_buf(call, |
418 | size: sizeof(struct yfs_xdr_YFSFetchStatus) + |
419 | sizeof(struct yfs_xdr_YFSCallBack) + |
420 | sizeof(struct yfs_xdr_YFSVolSync)); |
421 | fallthrough; |
422 | |
423 | /* extract the metadata */ |
424 | case 4: |
425 | ret = afs_extract_data(call, false); |
426 | if (ret < 0) |
427 | return ret; |
428 | |
429 | bp = call->buffer; |
430 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &vp->scb); |
431 | xdr_decode_YFSCallBack(bp: &bp, call, scb: &vp->scb); |
432 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
433 | |
434 | req->data_version = vp->scb.status.data_version; |
435 | req->file_size = vp->scb.status.size; |
436 | |
437 | call->unmarshall++; |
438 | fallthrough; |
439 | |
440 | case 5: |
441 | break; |
442 | } |
443 | |
444 | _leave(" = 0 [done]" ); |
445 | return 0; |
446 | } |
447 | |
448 | /* |
449 | * YFS.FetchData64 operation type |
450 | */ |
451 | static const struct afs_call_type yfs_RXYFSFetchData64 = { |
452 | .name = "YFS.FetchData64" , |
453 | .op = yfs_FS_FetchData64, |
454 | .deliver = yfs_deliver_fs_fetch_data64, |
455 | .destructor = afs_flat_call_destructor, |
456 | }; |
457 | |
458 | /* |
459 | * Fetch data from a file. |
460 | */ |
461 | void yfs_fs_fetch_data(struct afs_operation *op) |
462 | { |
463 | struct afs_vnode_param *vp = &op->file[0]; |
464 | struct afs_read *req = op->fetch.req; |
465 | struct afs_call *call; |
466 | __be32 *bp; |
467 | |
468 | _enter(",%x,{%llx:%llu},%llx,%llx" , |
469 | key_serial(op->key), vp->fid.vid, vp->fid.vnode, |
470 | req->pos, req->len); |
471 | |
472 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchData64, |
473 | sizeof(__be32) * 2 + |
474 | sizeof(struct yfs_xdr_YFSFid) + |
475 | sizeof(struct yfs_xdr_u64) * 2, |
476 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
477 | sizeof(struct yfs_xdr_YFSCallBack) + |
478 | sizeof(struct yfs_xdr_YFSVolSync)); |
479 | if (!call) |
480 | return afs_op_nomem(op); |
481 | |
482 | req->call_debug_id = call->debug_id; |
483 | |
484 | /* marshall the parameters */ |
485 | bp = call->request; |
486 | bp = xdr_encode_u32(bp, n: YFSFETCHDATA64); |
487 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
488 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
489 | bp = xdr_encode_u64(bp, n: req->pos); |
490 | bp = xdr_encode_u64(bp, n: req->len); |
491 | yfs_check_req(call, bp); |
492 | |
493 | trace_afs_make_fs_call(call, fid: &vp->fid); |
494 | afs_make_op_call(op, call, GFP_NOFS); |
495 | } |
496 | |
497 | /* |
498 | * Deliver reply data for YFS.CreateFile or YFS.MakeDir. |
499 | */ |
500 | static int yfs_deliver_fs_create_vnode(struct afs_call *call) |
501 | { |
502 | struct afs_operation *op = call->op; |
503 | struct afs_vnode_param *dvp = &op->file[0]; |
504 | struct afs_vnode_param *vp = &op->file[1]; |
505 | const __be32 *bp; |
506 | int ret; |
507 | |
508 | _enter("{%u}" , call->unmarshall); |
509 | |
510 | ret = afs_transfer_reply(call); |
511 | if (ret < 0) |
512 | return ret; |
513 | |
514 | /* unmarshall the reply once we've received all of it */ |
515 | bp = call->buffer; |
516 | xdr_decode_YFSFid(bp: &bp, fid: &op->file[1].fid); |
517 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &vp->scb); |
518 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &dvp->scb); |
519 | xdr_decode_YFSCallBack(bp: &bp, call, scb: &vp->scb); |
520 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
521 | |
522 | _leave(" = 0 [done]" ); |
523 | return 0; |
524 | } |
525 | |
526 | /* |
527 | * FS.CreateFile and FS.MakeDir operation type |
528 | */ |
529 | static const struct afs_call_type afs_RXFSCreateFile = { |
530 | .name = "YFS.CreateFile" , |
531 | .op = yfs_FS_CreateFile, |
532 | .deliver = yfs_deliver_fs_create_vnode, |
533 | .destructor = afs_flat_call_destructor, |
534 | }; |
535 | |
536 | /* |
537 | * Create a file. |
538 | */ |
539 | void yfs_fs_create_file(struct afs_operation *op) |
540 | { |
541 | const struct qstr *name = &op->dentry->d_name; |
542 | struct afs_vnode_param *dvp = &op->file[0]; |
543 | struct afs_call *call; |
544 | size_t reqsz, rplsz; |
545 | __be32 *bp; |
546 | |
547 | _enter("" ); |
548 | |
549 | reqsz = (sizeof(__be32) + |
550 | sizeof(__be32) + |
551 | sizeof(struct yfs_xdr_YFSFid) + |
552 | xdr_strlen(len: name->len) + |
553 | sizeof(struct yfs_xdr_YFSStoreStatus) + |
554 | sizeof(__be32)); |
555 | rplsz = (sizeof(struct yfs_xdr_YFSFid) + |
556 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
557 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
558 | sizeof(struct yfs_xdr_YFSCallBack) + |
559 | sizeof(struct yfs_xdr_YFSVolSync)); |
560 | |
561 | call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile, reqsz, rplsz); |
562 | if (!call) |
563 | return afs_op_nomem(op); |
564 | |
565 | /* marshall the parameters */ |
566 | bp = call->request; |
567 | bp = xdr_encode_u32(bp, n: YFSCREATEFILE); |
568 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
569 | bp = xdr_encode_YFSFid(bp, fid: &dvp->fid); |
570 | bp = xdr_encode_name(bp, p: name); |
571 | bp = xdr_encode_YFSStoreStatus(bp, mode: &op->create.mode, t: &op->mtime); |
572 | bp = xdr_encode_u32(bp, n: yfs_LockNone); /* ViceLockType */ |
573 | yfs_check_req(call, bp); |
574 | |
575 | trace_afs_make_fs_call1(call, fid: &dvp->fid, name); |
576 | afs_make_op_call(op, call, GFP_NOFS); |
577 | } |
578 | |
579 | static const struct afs_call_type yfs_RXFSMakeDir = { |
580 | .name = "YFS.MakeDir" , |
581 | .op = yfs_FS_MakeDir, |
582 | .deliver = yfs_deliver_fs_create_vnode, |
583 | .destructor = afs_flat_call_destructor, |
584 | }; |
585 | |
586 | /* |
587 | * Make a directory. |
588 | */ |
589 | void yfs_fs_make_dir(struct afs_operation *op) |
590 | { |
591 | const struct qstr *name = &op->dentry->d_name; |
592 | struct afs_vnode_param *dvp = &op->file[0]; |
593 | struct afs_call *call; |
594 | size_t reqsz, rplsz; |
595 | __be32 *bp; |
596 | |
597 | _enter("" ); |
598 | |
599 | reqsz = (sizeof(__be32) + |
600 | sizeof(struct yfs_xdr_RPCFlags) + |
601 | sizeof(struct yfs_xdr_YFSFid) + |
602 | xdr_strlen(len: name->len) + |
603 | sizeof(struct yfs_xdr_YFSStoreStatus)); |
604 | rplsz = (sizeof(struct yfs_xdr_YFSFid) + |
605 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
606 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
607 | sizeof(struct yfs_xdr_YFSCallBack) + |
608 | sizeof(struct yfs_xdr_YFSVolSync)); |
609 | |
610 | call = afs_alloc_flat_call(op->net, &yfs_RXFSMakeDir, reqsz, rplsz); |
611 | if (!call) |
612 | return afs_op_nomem(op); |
613 | |
614 | /* marshall the parameters */ |
615 | bp = call->request; |
616 | bp = xdr_encode_u32(bp, n: YFSMAKEDIR); |
617 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
618 | bp = xdr_encode_YFSFid(bp, fid: &dvp->fid); |
619 | bp = xdr_encode_name(bp, p: name); |
620 | bp = xdr_encode_YFSStoreStatus(bp, mode: &op->create.mode, t: &op->mtime); |
621 | yfs_check_req(call, bp); |
622 | |
623 | trace_afs_make_fs_call1(call, fid: &dvp->fid, name); |
624 | afs_make_op_call(op, call, GFP_NOFS); |
625 | } |
626 | |
627 | /* |
628 | * Deliver reply data to a YFS.RemoveFile2 operation. |
629 | */ |
630 | static int yfs_deliver_fs_remove_file2(struct afs_call *call) |
631 | { |
632 | struct afs_operation *op = call->op; |
633 | struct afs_vnode_param *dvp = &op->file[0]; |
634 | struct afs_vnode_param *vp = &op->file[1]; |
635 | struct afs_fid fid; |
636 | const __be32 *bp; |
637 | int ret; |
638 | |
639 | _enter("{%u}" , call->unmarshall); |
640 | |
641 | ret = afs_transfer_reply(call); |
642 | if (ret < 0) |
643 | return ret; |
644 | |
645 | bp = call->buffer; |
646 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &dvp->scb); |
647 | xdr_decode_YFSFid(bp: &bp, fid: &fid); |
648 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &vp->scb); |
649 | /* Was deleted if vnode->status.abort_code == VNOVNODE. */ |
650 | |
651 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
652 | return 0; |
653 | } |
654 | |
655 | static void yfs_done_fs_remove_file2(struct afs_call *call) |
656 | { |
657 | if (call->error == -ECONNABORTED && |
658 | call->abort_code == RX_INVALID_OPERATION) { |
659 | set_bit(AFS_SERVER_FL_NO_RM2, addr: &call->server->flags); |
660 | call->op->flags |= AFS_OPERATION_DOWNGRADE; |
661 | } |
662 | } |
663 | |
664 | /* |
665 | * YFS.RemoveFile2 operation type. |
666 | */ |
667 | static const struct afs_call_type yfs_RXYFSRemoveFile2 = { |
668 | .name = "YFS.RemoveFile2" , |
669 | .op = yfs_FS_RemoveFile2, |
670 | .deliver = yfs_deliver_fs_remove_file2, |
671 | .done = yfs_done_fs_remove_file2, |
672 | .destructor = afs_flat_call_destructor, |
673 | }; |
674 | |
675 | /* |
676 | * Remove a file and retrieve new file status. |
677 | */ |
678 | void yfs_fs_remove_file2(struct afs_operation *op) |
679 | { |
680 | struct afs_vnode_param *dvp = &op->file[0]; |
681 | const struct qstr *name = &op->dentry->d_name; |
682 | struct afs_call *call; |
683 | __be32 *bp; |
684 | |
685 | _enter("" ); |
686 | |
687 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveFile2, |
688 | sizeof(__be32) + |
689 | sizeof(struct yfs_xdr_RPCFlags) + |
690 | sizeof(struct yfs_xdr_YFSFid) + |
691 | xdr_strlen(len: name->len), |
692 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
693 | sizeof(struct yfs_xdr_YFSFid) + |
694 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
695 | sizeof(struct yfs_xdr_YFSVolSync)); |
696 | if (!call) |
697 | return afs_op_nomem(op); |
698 | |
699 | /* marshall the parameters */ |
700 | bp = call->request; |
701 | bp = xdr_encode_u32(bp, n: YFSREMOVEFILE2); |
702 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
703 | bp = xdr_encode_YFSFid(bp, fid: &dvp->fid); |
704 | bp = xdr_encode_name(bp, p: name); |
705 | yfs_check_req(call, bp); |
706 | |
707 | trace_afs_make_fs_call1(call, fid: &dvp->fid, name); |
708 | afs_make_op_call(op, call, GFP_NOFS); |
709 | } |
710 | |
711 | /* |
712 | * Deliver reply data to a YFS.RemoveFile or YFS.RemoveDir operation. |
713 | */ |
714 | static int yfs_deliver_fs_remove(struct afs_call *call) |
715 | { |
716 | struct afs_operation *op = call->op; |
717 | struct afs_vnode_param *dvp = &op->file[0]; |
718 | const __be32 *bp; |
719 | int ret; |
720 | |
721 | _enter("{%u}" , call->unmarshall); |
722 | |
723 | ret = afs_transfer_reply(call); |
724 | if (ret < 0) |
725 | return ret; |
726 | |
727 | bp = call->buffer; |
728 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &dvp->scb); |
729 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
730 | return 0; |
731 | } |
732 | |
733 | /* |
734 | * FS.RemoveDir and FS.RemoveFile operation types. |
735 | */ |
736 | static const struct afs_call_type yfs_RXYFSRemoveFile = { |
737 | .name = "YFS.RemoveFile" , |
738 | .op = yfs_FS_RemoveFile, |
739 | .deliver = yfs_deliver_fs_remove, |
740 | .destructor = afs_flat_call_destructor, |
741 | }; |
742 | |
743 | /* |
744 | * Remove a file. |
745 | */ |
746 | void yfs_fs_remove_file(struct afs_operation *op) |
747 | { |
748 | const struct qstr *name = &op->dentry->d_name; |
749 | struct afs_vnode_param *dvp = &op->file[0]; |
750 | struct afs_call *call; |
751 | __be32 *bp; |
752 | |
753 | _enter("" ); |
754 | |
755 | if (!test_bit(AFS_SERVER_FL_NO_RM2, &op->server->flags)) |
756 | return yfs_fs_remove_file2(op); |
757 | |
758 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveFile, |
759 | sizeof(__be32) + |
760 | sizeof(struct yfs_xdr_RPCFlags) + |
761 | sizeof(struct yfs_xdr_YFSFid) + |
762 | xdr_strlen(len: name->len), |
763 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
764 | sizeof(struct yfs_xdr_YFSVolSync)); |
765 | if (!call) |
766 | return afs_op_nomem(op); |
767 | |
768 | /* marshall the parameters */ |
769 | bp = call->request; |
770 | bp = xdr_encode_u32(bp, n: YFSREMOVEFILE); |
771 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
772 | bp = xdr_encode_YFSFid(bp, fid: &dvp->fid); |
773 | bp = xdr_encode_name(bp, p: name); |
774 | yfs_check_req(call, bp); |
775 | |
776 | trace_afs_make_fs_call1(call, fid: &dvp->fid, name); |
777 | afs_make_op_call(op, call, GFP_NOFS); |
778 | } |
779 | |
780 | static const struct afs_call_type yfs_RXYFSRemoveDir = { |
781 | .name = "YFS.RemoveDir" , |
782 | .op = yfs_FS_RemoveDir, |
783 | .deliver = yfs_deliver_fs_remove, |
784 | .destructor = afs_flat_call_destructor, |
785 | }; |
786 | |
787 | /* |
788 | * Remove a directory. |
789 | */ |
790 | void yfs_fs_remove_dir(struct afs_operation *op) |
791 | { |
792 | const struct qstr *name = &op->dentry->d_name; |
793 | struct afs_vnode_param *dvp = &op->file[0]; |
794 | struct afs_call *call; |
795 | __be32 *bp; |
796 | |
797 | _enter("" ); |
798 | |
799 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveDir, |
800 | sizeof(__be32) + |
801 | sizeof(struct yfs_xdr_RPCFlags) + |
802 | sizeof(struct yfs_xdr_YFSFid) + |
803 | xdr_strlen(len: name->len), |
804 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
805 | sizeof(struct yfs_xdr_YFSVolSync)); |
806 | if (!call) |
807 | return afs_op_nomem(op); |
808 | |
809 | /* marshall the parameters */ |
810 | bp = call->request; |
811 | bp = xdr_encode_u32(bp, n: YFSREMOVEDIR); |
812 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
813 | bp = xdr_encode_YFSFid(bp, fid: &dvp->fid); |
814 | bp = xdr_encode_name(bp, p: name); |
815 | yfs_check_req(call, bp); |
816 | |
817 | trace_afs_make_fs_call1(call, fid: &dvp->fid, name); |
818 | afs_make_op_call(op, call, GFP_NOFS); |
819 | } |
820 | |
821 | /* |
822 | * Deliver reply data to a YFS.Link operation. |
823 | */ |
824 | static int yfs_deliver_fs_link(struct afs_call *call) |
825 | { |
826 | struct afs_operation *op = call->op; |
827 | struct afs_vnode_param *dvp = &op->file[0]; |
828 | struct afs_vnode_param *vp = &op->file[1]; |
829 | const __be32 *bp; |
830 | int ret; |
831 | |
832 | _enter("{%u}" , call->unmarshall); |
833 | |
834 | ret = afs_transfer_reply(call); |
835 | if (ret < 0) |
836 | return ret; |
837 | |
838 | bp = call->buffer; |
839 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &vp->scb); |
840 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &dvp->scb); |
841 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
842 | _leave(" = 0 [done]" ); |
843 | return 0; |
844 | } |
845 | |
846 | /* |
847 | * YFS.Link operation type. |
848 | */ |
849 | static const struct afs_call_type yfs_RXYFSLink = { |
850 | .name = "YFS.Link" , |
851 | .op = yfs_FS_Link, |
852 | .deliver = yfs_deliver_fs_link, |
853 | .destructor = afs_flat_call_destructor, |
854 | }; |
855 | |
856 | /* |
857 | * Make a hard link. |
858 | */ |
859 | void yfs_fs_link(struct afs_operation *op) |
860 | { |
861 | const struct qstr *name = &op->dentry->d_name; |
862 | struct afs_vnode_param *dvp = &op->file[0]; |
863 | struct afs_vnode_param *vp = &op->file[1]; |
864 | struct afs_call *call; |
865 | __be32 *bp; |
866 | |
867 | _enter("" ); |
868 | |
869 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSLink, |
870 | sizeof(__be32) + |
871 | sizeof(struct yfs_xdr_RPCFlags) + |
872 | sizeof(struct yfs_xdr_YFSFid) + |
873 | xdr_strlen(len: name->len) + |
874 | sizeof(struct yfs_xdr_YFSFid), |
875 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
876 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
877 | sizeof(struct yfs_xdr_YFSVolSync)); |
878 | if (!call) |
879 | return afs_op_nomem(op); |
880 | |
881 | /* marshall the parameters */ |
882 | bp = call->request; |
883 | bp = xdr_encode_u32(bp, n: YFSLINK); |
884 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
885 | bp = xdr_encode_YFSFid(bp, fid: &dvp->fid); |
886 | bp = xdr_encode_name(bp, p: name); |
887 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
888 | yfs_check_req(call, bp); |
889 | |
890 | trace_afs_make_fs_call1(call, fid: &vp->fid, name); |
891 | afs_make_op_call(op, call, GFP_NOFS); |
892 | } |
893 | |
894 | /* |
895 | * Deliver reply data to a YFS.Symlink operation. |
896 | */ |
897 | static int yfs_deliver_fs_symlink(struct afs_call *call) |
898 | { |
899 | struct afs_operation *op = call->op; |
900 | struct afs_vnode_param *dvp = &op->file[0]; |
901 | struct afs_vnode_param *vp = &op->file[1]; |
902 | const __be32 *bp; |
903 | int ret; |
904 | |
905 | _enter("{%u}" , call->unmarshall); |
906 | |
907 | ret = afs_transfer_reply(call); |
908 | if (ret < 0) |
909 | return ret; |
910 | |
911 | /* unmarshall the reply once we've received all of it */ |
912 | bp = call->buffer; |
913 | xdr_decode_YFSFid(bp: &bp, fid: &vp->fid); |
914 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &vp->scb); |
915 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &dvp->scb); |
916 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
917 | |
918 | _leave(" = 0 [done]" ); |
919 | return 0; |
920 | } |
921 | |
922 | /* |
923 | * YFS.Symlink operation type |
924 | */ |
925 | static const struct afs_call_type yfs_RXYFSSymlink = { |
926 | .name = "YFS.Symlink" , |
927 | .op = yfs_FS_Symlink, |
928 | .deliver = yfs_deliver_fs_symlink, |
929 | .destructor = afs_flat_call_destructor, |
930 | }; |
931 | |
932 | /* |
933 | * Create a symbolic link. |
934 | */ |
935 | void yfs_fs_symlink(struct afs_operation *op) |
936 | { |
937 | const struct qstr *name = &op->dentry->d_name; |
938 | struct afs_vnode_param *dvp = &op->file[0]; |
939 | struct afs_call *call; |
940 | size_t contents_sz; |
941 | mode_t mode = 0777; |
942 | __be32 *bp; |
943 | |
944 | _enter("" ); |
945 | |
946 | contents_sz = strlen(op->create.symlink); |
947 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSSymlink, |
948 | sizeof(__be32) + |
949 | sizeof(struct yfs_xdr_RPCFlags) + |
950 | sizeof(struct yfs_xdr_YFSFid) + |
951 | xdr_strlen(len: name->len) + |
952 | xdr_strlen(len: contents_sz) + |
953 | sizeof(struct yfs_xdr_YFSStoreStatus), |
954 | sizeof(struct yfs_xdr_YFSFid) + |
955 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
956 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
957 | sizeof(struct yfs_xdr_YFSVolSync)); |
958 | if (!call) |
959 | return afs_op_nomem(op); |
960 | |
961 | /* marshall the parameters */ |
962 | bp = call->request; |
963 | bp = xdr_encode_u32(bp, n: YFSSYMLINK); |
964 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
965 | bp = xdr_encode_YFSFid(bp, fid: &dvp->fid); |
966 | bp = xdr_encode_name(bp, p: name); |
967 | bp = xdr_encode_string(bp, p: op->create.symlink, len: contents_sz); |
968 | bp = xdr_encode_YFSStoreStatus(bp, mode: &mode, t: &op->mtime); |
969 | yfs_check_req(call, bp); |
970 | |
971 | trace_afs_make_fs_call1(call, fid: &dvp->fid, name); |
972 | afs_make_op_call(op, call, GFP_NOFS); |
973 | } |
974 | |
975 | /* |
976 | * Deliver reply data to a YFS.Rename operation. |
977 | */ |
978 | static int yfs_deliver_fs_rename(struct afs_call *call) |
979 | { |
980 | struct afs_operation *op = call->op; |
981 | struct afs_vnode_param *orig_dvp = &op->file[0]; |
982 | struct afs_vnode_param *new_dvp = &op->file[1]; |
983 | const __be32 *bp; |
984 | int ret; |
985 | |
986 | _enter("{%u}" , call->unmarshall); |
987 | |
988 | ret = afs_transfer_reply(call); |
989 | if (ret < 0) |
990 | return ret; |
991 | |
992 | bp = call->buffer; |
993 | /* If the two dirs are the same, we have two copies of the same status |
994 | * report, so we just decode it twice. |
995 | */ |
996 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &orig_dvp->scb); |
997 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &new_dvp->scb); |
998 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
999 | _leave(" = 0 [done]" ); |
1000 | return 0; |
1001 | } |
1002 | |
1003 | /* |
1004 | * YFS.Rename operation type |
1005 | */ |
1006 | static const struct afs_call_type yfs_RXYFSRename = { |
1007 | .name = "FS.Rename" , |
1008 | .op = yfs_FS_Rename, |
1009 | .deliver = yfs_deliver_fs_rename, |
1010 | .destructor = afs_flat_call_destructor, |
1011 | }; |
1012 | |
1013 | /* |
1014 | * Rename a file or directory. |
1015 | */ |
1016 | void yfs_fs_rename(struct afs_operation *op) |
1017 | { |
1018 | struct afs_vnode_param *orig_dvp = &op->file[0]; |
1019 | struct afs_vnode_param *new_dvp = &op->file[1]; |
1020 | const struct qstr *orig_name = &op->dentry->d_name; |
1021 | const struct qstr *new_name = &op->dentry_2->d_name; |
1022 | struct afs_call *call; |
1023 | __be32 *bp; |
1024 | |
1025 | _enter("" ); |
1026 | |
1027 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSRename, |
1028 | sizeof(__be32) + |
1029 | sizeof(struct yfs_xdr_RPCFlags) + |
1030 | sizeof(struct yfs_xdr_YFSFid) + |
1031 | xdr_strlen(len: orig_name->len) + |
1032 | sizeof(struct yfs_xdr_YFSFid) + |
1033 | xdr_strlen(len: new_name->len), |
1034 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1035 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1036 | sizeof(struct yfs_xdr_YFSVolSync)); |
1037 | if (!call) |
1038 | return afs_op_nomem(op); |
1039 | |
1040 | /* marshall the parameters */ |
1041 | bp = call->request; |
1042 | bp = xdr_encode_u32(bp, n: YFSRENAME); |
1043 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1044 | bp = xdr_encode_YFSFid(bp, fid: &orig_dvp->fid); |
1045 | bp = xdr_encode_name(bp, p: orig_name); |
1046 | bp = xdr_encode_YFSFid(bp, fid: &new_dvp->fid); |
1047 | bp = xdr_encode_name(bp, p: new_name); |
1048 | yfs_check_req(call, bp); |
1049 | |
1050 | trace_afs_make_fs_call2(call, fid: &orig_dvp->fid, name: orig_name, name2: new_name); |
1051 | afs_make_op_call(op, call, GFP_NOFS); |
1052 | } |
1053 | |
1054 | /* |
1055 | * YFS.StoreData64 operation type. |
1056 | */ |
1057 | static const struct afs_call_type yfs_RXYFSStoreData64 = { |
1058 | .name = "YFS.StoreData64" , |
1059 | .op = yfs_FS_StoreData64, |
1060 | .deliver = yfs_deliver_status_and_volsync, |
1061 | .destructor = afs_flat_call_destructor, |
1062 | }; |
1063 | |
1064 | /* |
1065 | * Store a set of pages to a large file. |
1066 | */ |
1067 | void yfs_fs_store_data(struct afs_operation *op) |
1068 | { |
1069 | struct afs_vnode_param *vp = &op->file[0]; |
1070 | struct afs_call *call; |
1071 | __be32 *bp; |
1072 | |
1073 | _enter(",%x,{%llx:%llu},," , |
1074 | key_serial(op->key), vp->fid.vid, vp->fid.vnode); |
1075 | |
1076 | _debug("size %llx, at %llx, i_size %llx" , |
1077 | (unsigned long long)op->store.size, |
1078 | (unsigned long long)op->store.pos, |
1079 | (unsigned long long)op->store.i_size); |
1080 | |
1081 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64, |
1082 | sizeof(__be32) + |
1083 | sizeof(__be32) + |
1084 | sizeof(struct yfs_xdr_YFSFid) + |
1085 | sizeof(struct yfs_xdr_YFSStoreStatus) + |
1086 | sizeof(struct yfs_xdr_u64) * 3, |
1087 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1088 | sizeof(struct yfs_xdr_YFSVolSync)); |
1089 | if (!call) |
1090 | return afs_op_nomem(op); |
1091 | |
1092 | call->write_iter = op->store.write_iter; |
1093 | |
1094 | /* marshall the parameters */ |
1095 | bp = call->request; |
1096 | bp = xdr_encode_u32(bp, n: YFSSTOREDATA64); |
1097 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1098 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1099 | bp = xdr_encode_YFSStoreStatus(bp, NULL, t: &op->mtime); |
1100 | bp = xdr_encode_u64(bp, n: op->store.pos); |
1101 | bp = xdr_encode_u64(bp, n: op->store.size); |
1102 | bp = xdr_encode_u64(bp, n: op->store.i_size); |
1103 | yfs_check_req(call, bp); |
1104 | |
1105 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1106 | afs_make_op_call(op, call, GFP_NOFS); |
1107 | } |
1108 | |
1109 | /* |
1110 | * YFS.StoreStatus operation type |
1111 | */ |
1112 | static const struct afs_call_type yfs_RXYFSStoreStatus = { |
1113 | .name = "YFS.StoreStatus" , |
1114 | .op = yfs_FS_StoreStatus, |
1115 | .deliver = yfs_deliver_status_and_volsync, |
1116 | .destructor = afs_flat_call_destructor, |
1117 | }; |
1118 | |
1119 | static const struct afs_call_type yfs_RXYFSStoreData64_as_Status = { |
1120 | .name = "YFS.StoreData64" , |
1121 | .op = yfs_FS_StoreData64, |
1122 | .deliver = yfs_deliver_status_and_volsync, |
1123 | .destructor = afs_flat_call_destructor, |
1124 | }; |
1125 | |
1126 | /* |
1127 | * Set the attributes on a file, using YFS.StoreData64 rather than |
1128 | * YFS.StoreStatus so as to alter the file size also. |
1129 | */ |
1130 | static void yfs_fs_setattr_size(struct afs_operation *op) |
1131 | { |
1132 | struct afs_vnode_param *vp = &op->file[0]; |
1133 | struct afs_call *call; |
1134 | struct iattr *attr = op->setattr.attr; |
1135 | __be32 *bp; |
1136 | |
1137 | _enter(",%x,{%llx:%llu},," , |
1138 | key_serial(op->key), vp->fid.vid, vp->fid.vnode); |
1139 | |
1140 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64_as_Status, |
1141 | sizeof(__be32) * 2 + |
1142 | sizeof(struct yfs_xdr_YFSFid) + |
1143 | sizeof(struct yfs_xdr_YFSStoreStatus) + |
1144 | sizeof(struct yfs_xdr_u64) * 3, |
1145 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1146 | sizeof(struct yfs_xdr_YFSVolSync)); |
1147 | if (!call) |
1148 | return afs_op_nomem(op); |
1149 | |
1150 | /* marshall the parameters */ |
1151 | bp = call->request; |
1152 | bp = xdr_encode_u32(bp, n: YFSSTOREDATA64); |
1153 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1154 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1155 | bp = xdr_encode_YFS_StoreStatus(bp, attr); |
1156 | bp = xdr_encode_u64(bp, n: attr->ia_size); /* position of start of write */ |
1157 | bp = xdr_encode_u64(bp, n: 0); /* size of write */ |
1158 | bp = xdr_encode_u64(bp, n: attr->ia_size); /* new file length */ |
1159 | yfs_check_req(call, bp); |
1160 | |
1161 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1162 | afs_make_op_call(op, call, GFP_NOFS); |
1163 | } |
1164 | |
1165 | /* |
1166 | * Set the attributes on a file, using YFS.StoreData64 if there's a change in |
1167 | * file size, and YFS.StoreStatus otherwise. |
1168 | */ |
1169 | void yfs_fs_setattr(struct afs_operation *op) |
1170 | { |
1171 | struct afs_vnode_param *vp = &op->file[0]; |
1172 | struct afs_call *call; |
1173 | struct iattr *attr = op->setattr.attr; |
1174 | __be32 *bp; |
1175 | |
1176 | if (attr->ia_valid & ATTR_SIZE) |
1177 | return yfs_fs_setattr_size(op); |
1178 | |
1179 | _enter(",%x,{%llx:%llu},," , |
1180 | key_serial(op->key), vp->fid.vid, vp->fid.vnode); |
1181 | |
1182 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreStatus, |
1183 | sizeof(__be32) * 2 + |
1184 | sizeof(struct yfs_xdr_YFSFid) + |
1185 | sizeof(struct yfs_xdr_YFSStoreStatus), |
1186 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1187 | sizeof(struct yfs_xdr_YFSVolSync)); |
1188 | if (!call) |
1189 | return afs_op_nomem(op); |
1190 | |
1191 | /* marshall the parameters */ |
1192 | bp = call->request; |
1193 | bp = xdr_encode_u32(bp, n: YFSSTORESTATUS); |
1194 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1195 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1196 | bp = xdr_encode_YFS_StoreStatus(bp, attr); |
1197 | yfs_check_req(call, bp); |
1198 | |
1199 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1200 | afs_make_op_call(op, call, GFP_NOFS); |
1201 | } |
1202 | |
1203 | /* |
1204 | * Deliver reply data to a YFS.GetVolumeStatus operation. |
1205 | */ |
1206 | static int yfs_deliver_fs_get_volume_status(struct afs_call *call) |
1207 | { |
1208 | struct afs_operation *op = call->op; |
1209 | const __be32 *bp; |
1210 | char *p; |
1211 | u32 size; |
1212 | int ret; |
1213 | |
1214 | _enter("{%u}" , call->unmarshall); |
1215 | |
1216 | switch (call->unmarshall) { |
1217 | case 0: |
1218 | call->unmarshall++; |
1219 | afs_extract_to_buf(call, size: sizeof(struct yfs_xdr_YFSFetchVolumeStatus)); |
1220 | fallthrough; |
1221 | |
1222 | /* extract the returned status record */ |
1223 | case 1: |
1224 | _debug("extract status" ); |
1225 | ret = afs_extract_data(call, true); |
1226 | if (ret < 0) |
1227 | return ret; |
1228 | |
1229 | bp = call->buffer; |
1230 | xdr_decode_YFSFetchVolumeStatus(bp: &bp, vs: &op->volstatus.vs); |
1231 | call->unmarshall++; |
1232 | afs_extract_to_tmp(call); |
1233 | fallthrough; |
1234 | |
1235 | /* extract the volume name length */ |
1236 | case 2: |
1237 | ret = afs_extract_data(call, true); |
1238 | if (ret < 0) |
1239 | return ret; |
1240 | |
1241 | call->count = ntohl(call->tmp); |
1242 | _debug("volname length: %u" , call->count); |
1243 | if (call->count >= AFSNAMEMAX) |
1244 | return afs_protocol_error(call, afs_eproto_volname_len); |
1245 | size = (call->count + 3) & ~3; /* It's padded */ |
1246 | afs_extract_to_buf(call, size); |
1247 | call->unmarshall++; |
1248 | fallthrough; |
1249 | |
1250 | /* extract the volume name */ |
1251 | case 3: |
1252 | _debug("extract volname" ); |
1253 | ret = afs_extract_data(call, true); |
1254 | if (ret < 0) |
1255 | return ret; |
1256 | |
1257 | p = call->buffer; |
1258 | p[call->count] = 0; |
1259 | _debug("volname '%s'" , p); |
1260 | afs_extract_to_tmp(call); |
1261 | call->unmarshall++; |
1262 | fallthrough; |
1263 | |
1264 | /* extract the offline message length */ |
1265 | case 4: |
1266 | ret = afs_extract_data(call, true); |
1267 | if (ret < 0) |
1268 | return ret; |
1269 | |
1270 | call->count = ntohl(call->tmp); |
1271 | _debug("offline msg length: %u" , call->count); |
1272 | if (call->count >= AFSNAMEMAX) |
1273 | return afs_protocol_error(call, afs_eproto_offline_msg_len); |
1274 | size = (call->count + 3) & ~3; /* It's padded */ |
1275 | afs_extract_to_buf(call, size); |
1276 | call->unmarshall++; |
1277 | fallthrough; |
1278 | |
1279 | /* extract the offline message */ |
1280 | case 5: |
1281 | _debug("extract offline" ); |
1282 | ret = afs_extract_data(call, true); |
1283 | if (ret < 0) |
1284 | return ret; |
1285 | |
1286 | p = call->buffer; |
1287 | p[call->count] = 0; |
1288 | _debug("offline '%s'" , p); |
1289 | |
1290 | afs_extract_to_tmp(call); |
1291 | call->unmarshall++; |
1292 | fallthrough; |
1293 | |
1294 | /* extract the message of the day length */ |
1295 | case 6: |
1296 | ret = afs_extract_data(call, true); |
1297 | if (ret < 0) |
1298 | return ret; |
1299 | |
1300 | call->count = ntohl(call->tmp); |
1301 | _debug("motd length: %u" , call->count); |
1302 | if (call->count >= AFSNAMEMAX) |
1303 | return afs_protocol_error(call, afs_eproto_motd_len); |
1304 | size = (call->count + 3) & ~3; /* It's padded */ |
1305 | afs_extract_to_buf(call, size); |
1306 | call->unmarshall++; |
1307 | fallthrough; |
1308 | |
1309 | /* extract the message of the day */ |
1310 | case 7: |
1311 | _debug("extract motd" ); |
1312 | ret = afs_extract_data(call, false); |
1313 | if (ret < 0) |
1314 | return ret; |
1315 | |
1316 | p = call->buffer; |
1317 | p[call->count] = 0; |
1318 | _debug("motd '%s'" , p); |
1319 | |
1320 | call->unmarshall++; |
1321 | fallthrough; |
1322 | |
1323 | case 8: |
1324 | break; |
1325 | } |
1326 | |
1327 | _leave(" = 0 [done]" ); |
1328 | return 0; |
1329 | } |
1330 | |
1331 | /* |
1332 | * YFS.GetVolumeStatus operation type |
1333 | */ |
1334 | static const struct afs_call_type yfs_RXYFSGetVolumeStatus = { |
1335 | .name = "YFS.GetVolumeStatus" , |
1336 | .op = yfs_FS_GetVolumeStatus, |
1337 | .deliver = yfs_deliver_fs_get_volume_status, |
1338 | .destructor = afs_flat_call_destructor, |
1339 | }; |
1340 | |
1341 | /* |
1342 | * fetch the status of a volume |
1343 | */ |
1344 | void yfs_fs_get_volume_status(struct afs_operation *op) |
1345 | { |
1346 | struct afs_vnode_param *vp = &op->file[0]; |
1347 | struct afs_call *call; |
1348 | __be32 *bp; |
1349 | |
1350 | _enter("" ); |
1351 | |
1352 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSGetVolumeStatus, |
1353 | sizeof(__be32) * 2 + |
1354 | sizeof(struct yfs_xdr_u64), |
1355 | max_t(size_t, |
1356 | sizeof(struct yfs_xdr_YFSFetchVolumeStatus) + |
1357 | sizeof(__be32), |
1358 | AFSOPAQUEMAX + 1)); |
1359 | if (!call) |
1360 | return afs_op_nomem(op); |
1361 | |
1362 | /* marshall the parameters */ |
1363 | bp = call->request; |
1364 | bp = xdr_encode_u32(bp, n: YFSGETVOLUMESTATUS); |
1365 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1366 | bp = xdr_encode_u64(bp, n: vp->fid.vid); |
1367 | yfs_check_req(call, bp); |
1368 | |
1369 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1370 | afs_make_op_call(op, call, GFP_NOFS); |
1371 | } |
1372 | |
1373 | /* |
1374 | * YFS.SetLock operation type |
1375 | */ |
1376 | static const struct afs_call_type yfs_RXYFSSetLock = { |
1377 | .name = "YFS.SetLock" , |
1378 | .op = yfs_FS_SetLock, |
1379 | .deliver = yfs_deliver_status_and_volsync, |
1380 | .done = afs_lock_op_done, |
1381 | .destructor = afs_flat_call_destructor, |
1382 | }; |
1383 | |
1384 | /* |
1385 | * YFS.ExtendLock operation type |
1386 | */ |
1387 | static const struct afs_call_type yfs_RXYFSExtendLock = { |
1388 | .name = "YFS.ExtendLock" , |
1389 | .op = yfs_FS_ExtendLock, |
1390 | .deliver = yfs_deliver_status_and_volsync, |
1391 | .done = afs_lock_op_done, |
1392 | .destructor = afs_flat_call_destructor, |
1393 | }; |
1394 | |
1395 | /* |
1396 | * YFS.ReleaseLock operation type |
1397 | */ |
1398 | static const struct afs_call_type yfs_RXYFSReleaseLock = { |
1399 | .name = "YFS.ReleaseLock" , |
1400 | .op = yfs_FS_ReleaseLock, |
1401 | .deliver = yfs_deliver_status_and_volsync, |
1402 | .destructor = afs_flat_call_destructor, |
1403 | }; |
1404 | |
1405 | /* |
1406 | * Set a lock on a file |
1407 | */ |
1408 | void yfs_fs_set_lock(struct afs_operation *op) |
1409 | { |
1410 | struct afs_vnode_param *vp = &op->file[0]; |
1411 | struct afs_call *call; |
1412 | __be32 *bp; |
1413 | |
1414 | _enter("" ); |
1415 | |
1416 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSSetLock, |
1417 | sizeof(__be32) * 2 + |
1418 | sizeof(struct yfs_xdr_YFSFid) + |
1419 | sizeof(__be32), |
1420 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1421 | sizeof(struct yfs_xdr_YFSVolSync)); |
1422 | if (!call) |
1423 | return afs_op_nomem(op); |
1424 | |
1425 | /* marshall the parameters */ |
1426 | bp = call->request; |
1427 | bp = xdr_encode_u32(bp, n: YFSSETLOCK); |
1428 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1429 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1430 | bp = xdr_encode_u32(bp, n: op->lock.type); |
1431 | yfs_check_req(call, bp); |
1432 | |
1433 | trace_afs_make_fs_calli(call, fid: &vp->fid, i: op->lock.type); |
1434 | afs_make_op_call(op, call, GFP_NOFS); |
1435 | } |
1436 | |
1437 | /* |
1438 | * extend a lock on a file |
1439 | */ |
1440 | void yfs_fs_extend_lock(struct afs_operation *op) |
1441 | { |
1442 | struct afs_vnode_param *vp = &op->file[0]; |
1443 | struct afs_call *call; |
1444 | __be32 *bp; |
1445 | |
1446 | _enter("" ); |
1447 | |
1448 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSExtendLock, |
1449 | sizeof(__be32) * 2 + |
1450 | sizeof(struct yfs_xdr_YFSFid), |
1451 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1452 | sizeof(struct yfs_xdr_YFSVolSync)); |
1453 | if (!call) |
1454 | return afs_op_nomem(op); |
1455 | |
1456 | /* marshall the parameters */ |
1457 | bp = call->request; |
1458 | bp = xdr_encode_u32(bp, n: YFSEXTENDLOCK); |
1459 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1460 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1461 | yfs_check_req(call, bp); |
1462 | |
1463 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1464 | afs_make_op_call(op, call, GFP_NOFS); |
1465 | } |
1466 | |
1467 | /* |
1468 | * release a lock on a file |
1469 | */ |
1470 | void yfs_fs_release_lock(struct afs_operation *op) |
1471 | { |
1472 | struct afs_vnode_param *vp = &op->file[0]; |
1473 | struct afs_call *call; |
1474 | __be32 *bp; |
1475 | |
1476 | _enter("" ); |
1477 | |
1478 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSReleaseLock, |
1479 | sizeof(__be32) * 2 + |
1480 | sizeof(struct yfs_xdr_YFSFid), |
1481 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1482 | sizeof(struct yfs_xdr_YFSVolSync)); |
1483 | if (!call) |
1484 | return afs_op_nomem(op); |
1485 | |
1486 | /* marshall the parameters */ |
1487 | bp = call->request; |
1488 | bp = xdr_encode_u32(bp, n: YFSRELEASELOCK); |
1489 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1490 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1491 | yfs_check_req(call, bp); |
1492 | |
1493 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1494 | afs_make_op_call(op, call, GFP_NOFS); |
1495 | } |
1496 | |
1497 | /* |
1498 | * Deliver a reply to YFS.FetchStatus |
1499 | */ |
1500 | static int yfs_deliver_fs_fetch_status(struct afs_call *call) |
1501 | { |
1502 | struct afs_operation *op = call->op; |
1503 | struct afs_vnode_param *vp = &op->file[op->fetch_status.which]; |
1504 | const __be32 *bp; |
1505 | int ret; |
1506 | |
1507 | ret = afs_transfer_reply(call); |
1508 | if (ret < 0) |
1509 | return ret; |
1510 | |
1511 | /* unmarshall the reply once we've received all of it */ |
1512 | bp = call->buffer; |
1513 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &vp->scb); |
1514 | xdr_decode_YFSCallBack(bp: &bp, call, scb: &vp->scb); |
1515 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
1516 | |
1517 | _leave(" = 0 [done]" ); |
1518 | return 0; |
1519 | } |
1520 | |
1521 | /* |
1522 | * YFS.FetchStatus operation type |
1523 | */ |
1524 | static const struct afs_call_type yfs_RXYFSFetchStatus = { |
1525 | .name = "YFS.FetchStatus" , |
1526 | .op = yfs_FS_FetchStatus, |
1527 | .deliver = yfs_deliver_fs_fetch_status, |
1528 | .destructor = afs_flat_call_destructor, |
1529 | }; |
1530 | |
1531 | /* |
1532 | * Fetch the status information for a fid without needing a vnode handle. |
1533 | */ |
1534 | void yfs_fs_fetch_status(struct afs_operation *op) |
1535 | { |
1536 | struct afs_vnode_param *vp = &op->file[op->fetch_status.which]; |
1537 | struct afs_call *call; |
1538 | __be32 *bp; |
1539 | |
1540 | _enter(",%x,{%llx:%llu},," , |
1541 | key_serial(op->key), vp->fid.vid, vp->fid.vnode); |
1542 | |
1543 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchStatus, |
1544 | sizeof(__be32) * 2 + |
1545 | sizeof(struct yfs_xdr_YFSFid), |
1546 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1547 | sizeof(struct yfs_xdr_YFSCallBack) + |
1548 | sizeof(struct yfs_xdr_YFSVolSync)); |
1549 | if (!call) |
1550 | return afs_op_nomem(op); |
1551 | |
1552 | /* marshall the parameters */ |
1553 | bp = call->request; |
1554 | bp = xdr_encode_u32(bp, n: YFSFETCHSTATUS); |
1555 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1556 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1557 | yfs_check_req(call, bp); |
1558 | |
1559 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1560 | afs_make_op_call(op, call, GFP_NOFS); |
1561 | } |
1562 | |
1563 | /* |
1564 | * Deliver reply data to an YFS.InlineBulkStatus call |
1565 | */ |
1566 | static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) |
1567 | { |
1568 | struct afs_operation *op = call->op; |
1569 | struct afs_status_cb *scb; |
1570 | const __be32 *bp; |
1571 | u32 tmp; |
1572 | int ret; |
1573 | |
1574 | _enter("{%u}" , call->unmarshall); |
1575 | |
1576 | switch (call->unmarshall) { |
1577 | case 0: |
1578 | afs_extract_to_tmp(call); |
1579 | call->unmarshall++; |
1580 | fallthrough; |
1581 | |
1582 | /* Extract the file status count and array in two steps */ |
1583 | case 1: |
1584 | _debug("extract status count" ); |
1585 | ret = afs_extract_data(call, true); |
1586 | if (ret < 0) |
1587 | return ret; |
1588 | |
1589 | tmp = ntohl(call->tmp); |
1590 | _debug("status count: %u/%u" , tmp, op->nr_files); |
1591 | if (tmp != op->nr_files) |
1592 | return afs_protocol_error(call, afs_eproto_ibulkst_count); |
1593 | |
1594 | call->count = 0; |
1595 | call->unmarshall++; |
1596 | more_counts: |
1597 | afs_extract_to_buf(call, size: sizeof(struct yfs_xdr_YFSFetchStatus)); |
1598 | fallthrough; |
1599 | |
1600 | case 2: |
1601 | _debug("extract status array %u" , call->count); |
1602 | ret = afs_extract_data(call, true); |
1603 | if (ret < 0) |
1604 | return ret; |
1605 | |
1606 | switch (call->count) { |
1607 | case 0: |
1608 | scb = &op->file[0].scb; |
1609 | break; |
1610 | case 1: |
1611 | scb = &op->file[1].scb; |
1612 | break; |
1613 | default: |
1614 | scb = &op->more_files[call->count - 2].scb; |
1615 | break; |
1616 | } |
1617 | |
1618 | bp = call->buffer; |
1619 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb); |
1620 | |
1621 | call->count++; |
1622 | if (call->count < op->nr_files) |
1623 | goto more_counts; |
1624 | |
1625 | call->count = 0; |
1626 | call->unmarshall++; |
1627 | afs_extract_to_tmp(call); |
1628 | fallthrough; |
1629 | |
1630 | /* Extract the callback count and array in two steps */ |
1631 | case 3: |
1632 | _debug("extract CB count" ); |
1633 | ret = afs_extract_data(call, true); |
1634 | if (ret < 0) |
1635 | return ret; |
1636 | |
1637 | tmp = ntohl(call->tmp); |
1638 | _debug("CB count: %u" , tmp); |
1639 | if (tmp != op->nr_files) |
1640 | return afs_protocol_error(call, afs_eproto_ibulkst_cb_count); |
1641 | call->count = 0; |
1642 | call->unmarshall++; |
1643 | more_cbs: |
1644 | afs_extract_to_buf(call, size: sizeof(struct yfs_xdr_YFSCallBack)); |
1645 | fallthrough; |
1646 | |
1647 | case 4: |
1648 | _debug("extract CB array" ); |
1649 | ret = afs_extract_data(call, true); |
1650 | if (ret < 0) |
1651 | return ret; |
1652 | |
1653 | _debug("unmarshall CB array" ); |
1654 | switch (call->count) { |
1655 | case 0: |
1656 | scb = &op->file[0].scb; |
1657 | break; |
1658 | case 1: |
1659 | scb = &op->file[1].scb; |
1660 | break; |
1661 | default: |
1662 | scb = &op->more_files[call->count - 2].scb; |
1663 | break; |
1664 | } |
1665 | |
1666 | bp = call->buffer; |
1667 | xdr_decode_YFSCallBack(bp: &bp, call, scb); |
1668 | call->count++; |
1669 | if (call->count < op->nr_files) |
1670 | goto more_cbs; |
1671 | |
1672 | afs_extract_to_buf(call, size: sizeof(struct yfs_xdr_YFSVolSync)); |
1673 | call->unmarshall++; |
1674 | fallthrough; |
1675 | |
1676 | case 5: |
1677 | ret = afs_extract_data(call, false); |
1678 | if (ret < 0) |
1679 | return ret; |
1680 | |
1681 | bp = call->buffer; |
1682 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
1683 | |
1684 | call->unmarshall++; |
1685 | fallthrough; |
1686 | |
1687 | case 6: |
1688 | break; |
1689 | } |
1690 | |
1691 | _leave(" = 0 [done]" ); |
1692 | return 0; |
1693 | } |
1694 | |
1695 | /* |
1696 | * FS.InlineBulkStatus operation type |
1697 | */ |
1698 | static const struct afs_call_type yfs_RXYFSInlineBulkStatus = { |
1699 | .name = "YFS.InlineBulkStatus" , |
1700 | .op = yfs_FS_InlineBulkStatus, |
1701 | .deliver = yfs_deliver_fs_inline_bulk_status, |
1702 | .destructor = afs_flat_call_destructor, |
1703 | }; |
1704 | |
1705 | /* |
1706 | * Fetch the status information for up to 1024 files |
1707 | */ |
1708 | void yfs_fs_inline_bulk_status(struct afs_operation *op) |
1709 | { |
1710 | struct afs_vnode_param *dvp = &op->file[0]; |
1711 | struct afs_vnode_param *vp = &op->file[1]; |
1712 | struct afs_call *call; |
1713 | __be32 *bp; |
1714 | int i; |
1715 | |
1716 | _enter(",%x,{%llx:%llu},%u" , |
1717 | key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files); |
1718 | |
1719 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSInlineBulkStatus, |
1720 | sizeof(__be32) + |
1721 | sizeof(__be32) + |
1722 | sizeof(__be32) + |
1723 | sizeof(struct yfs_xdr_YFSFid) * op->nr_files, |
1724 | sizeof(struct yfs_xdr_YFSFetchStatus)); |
1725 | if (!call) |
1726 | return afs_op_nomem(op); |
1727 | |
1728 | /* marshall the parameters */ |
1729 | bp = call->request; |
1730 | bp = xdr_encode_u32(bp, n: YFSINLINEBULKSTATUS); |
1731 | bp = xdr_encode_u32(bp, n: 0); /* RPCFlags */ |
1732 | bp = xdr_encode_u32(bp, n: op->nr_files); |
1733 | bp = xdr_encode_YFSFid(bp, fid: &dvp->fid); |
1734 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1735 | for (i = 0; i < op->nr_files - 2; i++) |
1736 | bp = xdr_encode_YFSFid(bp, fid: &op->more_files[i].fid); |
1737 | yfs_check_req(call, bp); |
1738 | |
1739 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1740 | afs_make_op_call(op, call, GFP_NOFS); |
1741 | } |
1742 | |
1743 | /* |
1744 | * Deliver reply data to an YFS.FetchOpaqueACL. |
1745 | */ |
1746 | static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call) |
1747 | { |
1748 | struct afs_operation *op = call->op; |
1749 | struct afs_vnode_param *vp = &op->file[0]; |
1750 | struct yfs_acl *yacl = op->yacl; |
1751 | struct afs_acl *acl; |
1752 | const __be32 *bp; |
1753 | unsigned int size; |
1754 | int ret; |
1755 | |
1756 | _enter("{%u}" , call->unmarshall); |
1757 | |
1758 | switch (call->unmarshall) { |
1759 | case 0: |
1760 | afs_extract_to_tmp(call); |
1761 | call->unmarshall++; |
1762 | fallthrough; |
1763 | |
1764 | /* Extract the file ACL length */ |
1765 | case 1: |
1766 | ret = afs_extract_data(call, true); |
1767 | if (ret < 0) |
1768 | return ret; |
1769 | |
1770 | size = call->count2 = ntohl(call->tmp); |
1771 | size = round_up(size, 4); |
1772 | |
1773 | if (yacl->flags & YFS_ACL_WANT_ACL) { |
1774 | acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL); |
1775 | if (!acl) |
1776 | return -ENOMEM; |
1777 | yacl->acl = acl; |
1778 | acl->size = call->count2; |
1779 | afs_extract_begin(call, buf: acl->data, size); |
1780 | } else { |
1781 | afs_extract_discard(call, size); |
1782 | } |
1783 | call->unmarshall++; |
1784 | fallthrough; |
1785 | |
1786 | /* Extract the file ACL */ |
1787 | case 2: |
1788 | ret = afs_extract_data(call, true); |
1789 | if (ret < 0) |
1790 | return ret; |
1791 | |
1792 | afs_extract_to_tmp(call); |
1793 | call->unmarshall++; |
1794 | fallthrough; |
1795 | |
1796 | /* Extract the volume ACL length */ |
1797 | case 3: |
1798 | ret = afs_extract_data(call, true); |
1799 | if (ret < 0) |
1800 | return ret; |
1801 | |
1802 | size = call->count2 = ntohl(call->tmp); |
1803 | size = round_up(size, 4); |
1804 | |
1805 | if (yacl->flags & YFS_ACL_WANT_VOL_ACL) { |
1806 | acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL); |
1807 | if (!acl) |
1808 | return -ENOMEM; |
1809 | yacl->vol_acl = acl; |
1810 | acl->size = call->count2; |
1811 | afs_extract_begin(call, buf: acl->data, size); |
1812 | } else { |
1813 | afs_extract_discard(call, size); |
1814 | } |
1815 | call->unmarshall++; |
1816 | fallthrough; |
1817 | |
1818 | /* Extract the volume ACL */ |
1819 | case 4: |
1820 | ret = afs_extract_data(call, true); |
1821 | if (ret < 0) |
1822 | return ret; |
1823 | |
1824 | afs_extract_to_buf(call, |
1825 | size: sizeof(__be32) * 2 + |
1826 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1827 | sizeof(struct yfs_xdr_YFSVolSync)); |
1828 | call->unmarshall++; |
1829 | fallthrough; |
1830 | |
1831 | /* extract the metadata */ |
1832 | case 5: |
1833 | ret = afs_extract_data(call, false); |
1834 | if (ret < 0) |
1835 | return ret; |
1836 | |
1837 | bp = call->buffer; |
1838 | yacl->inherit_flag = ntohl(*bp++); |
1839 | yacl->num_cleaned = ntohl(*bp++); |
1840 | xdr_decode_YFSFetchStatus(bp: &bp, call, scb: &vp->scb); |
1841 | xdr_decode_YFSVolSync(bp: &bp, volsync: &op->volsync); |
1842 | |
1843 | call->unmarshall++; |
1844 | fallthrough; |
1845 | |
1846 | case 6: |
1847 | break; |
1848 | } |
1849 | |
1850 | _leave(" = 0 [done]" ); |
1851 | return 0; |
1852 | } |
1853 | |
1854 | void yfs_free_opaque_acl(struct yfs_acl *yacl) |
1855 | { |
1856 | if (yacl) { |
1857 | kfree(objp: yacl->acl); |
1858 | kfree(objp: yacl->vol_acl); |
1859 | kfree(objp: yacl); |
1860 | } |
1861 | } |
1862 | |
1863 | /* |
1864 | * YFS.FetchOpaqueACL operation type |
1865 | */ |
1866 | static const struct afs_call_type yfs_RXYFSFetchOpaqueACL = { |
1867 | .name = "YFS.FetchOpaqueACL" , |
1868 | .op = yfs_FS_FetchOpaqueACL, |
1869 | .deliver = yfs_deliver_fs_fetch_opaque_acl, |
1870 | .destructor = afs_flat_call_destructor, |
1871 | }; |
1872 | |
1873 | /* |
1874 | * Fetch the YFS advanced ACLs for a file. |
1875 | */ |
1876 | void yfs_fs_fetch_opaque_acl(struct afs_operation *op) |
1877 | { |
1878 | struct afs_vnode_param *vp = &op->file[0]; |
1879 | struct afs_call *call; |
1880 | __be32 *bp; |
1881 | |
1882 | _enter(",%x,{%llx:%llu},," , |
1883 | key_serial(op->key), vp->fid.vid, vp->fid.vnode); |
1884 | |
1885 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchOpaqueACL, |
1886 | sizeof(__be32) * 2 + |
1887 | sizeof(struct yfs_xdr_YFSFid), |
1888 | sizeof(__be32) * 2 + |
1889 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1890 | sizeof(struct yfs_xdr_YFSVolSync)); |
1891 | if (!call) |
1892 | return afs_op_nomem(op); |
1893 | |
1894 | /* marshall the parameters */ |
1895 | bp = call->request; |
1896 | bp = xdr_encode_u32(bp, n: YFSFETCHOPAQUEACL); |
1897 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1898 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1899 | yfs_check_req(call, bp); |
1900 | |
1901 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1902 | afs_make_op_call(op, call, GFP_KERNEL); |
1903 | } |
1904 | |
1905 | /* |
1906 | * YFS.StoreOpaqueACL2 operation type |
1907 | */ |
1908 | static const struct afs_call_type yfs_RXYFSStoreOpaqueACL2 = { |
1909 | .name = "YFS.StoreOpaqueACL2" , |
1910 | .op = yfs_FS_StoreOpaqueACL2, |
1911 | .deliver = yfs_deliver_status_and_volsync, |
1912 | .destructor = afs_flat_call_destructor, |
1913 | }; |
1914 | |
1915 | /* |
1916 | * Fetch the YFS ACL for a file. |
1917 | */ |
1918 | void yfs_fs_store_opaque_acl2(struct afs_operation *op) |
1919 | { |
1920 | struct afs_vnode_param *vp = &op->file[0]; |
1921 | struct afs_call *call; |
1922 | struct afs_acl *acl = op->acl; |
1923 | size_t size; |
1924 | __be32 *bp; |
1925 | |
1926 | _enter(",%x,{%llx:%llu},," , |
1927 | key_serial(op->key), vp->fid.vid, vp->fid.vnode); |
1928 | |
1929 | size = round_up(acl->size, 4); |
1930 | call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreOpaqueACL2, |
1931 | sizeof(__be32) * 2 + |
1932 | sizeof(struct yfs_xdr_YFSFid) + |
1933 | sizeof(__be32) + size, |
1934 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
1935 | sizeof(struct yfs_xdr_YFSVolSync)); |
1936 | if (!call) |
1937 | return afs_op_nomem(op); |
1938 | |
1939 | /* marshall the parameters */ |
1940 | bp = call->request; |
1941 | bp = xdr_encode_u32(bp, n: YFSSTOREOPAQUEACL2); |
1942 | bp = xdr_encode_u32(bp, n: 0); /* RPC flags */ |
1943 | bp = xdr_encode_YFSFid(bp, fid: &vp->fid); |
1944 | bp = xdr_encode_u32(bp, n: acl->size); |
1945 | memcpy(bp, acl->data, acl->size); |
1946 | if (acl->size != size) |
1947 | memset((void *)bp + acl->size, 0, size - acl->size); |
1948 | bp += size / sizeof(__be32); |
1949 | yfs_check_req(call, bp); |
1950 | |
1951 | trace_afs_make_fs_call(call, fid: &vp->fid); |
1952 | afs_make_op_call(op, call, GFP_KERNEL); |
1953 | } |
1954 | |