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