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