diff options
author | David Howells <dhowells@redhat.com> | 2007-04-26 18:59:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-04-26 18:59:35 -0400 |
commit | 260a980317dac80182dd76140cf67c6e81d6d3dd (patch) | |
tree | 84f3e919fd33be56aad4fc57f5cb844df1a6b952 /fs/afs/fsclient.c | |
parent | c35eccb1f614954b10cba3f74b7c301993b2f42e (diff) |
[AFS]: Add "directory write" support.
Add support for the create, link, symlink, unlink, mkdir, rmdir and
rename VFS operations to the in-kernel AFS filesystem.
Also:
(1) Fix dentry and inode revalidation. d_revalidate should only look at
state of the dentry. Revalidation of the contents of an inode pointed to
by a dentry is now separate.
(2) Fix afs_lookup() to hash negative dentries as well as positive ones.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'fs/afs/fsclient.c')
-rw-r--r-- | fs/afs/fsclient.c | 625 |
1 files changed, 574 insertions, 51 deletions
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 321b489aa90f..f036b4cc51a6 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -16,14 +16,28 @@ | |||
16 | #include "afs_fs.h" | 16 | #include "afs_fs.h" |
17 | 17 | ||
18 | /* | 18 | /* |
19 | * decode an AFSFid block | ||
20 | */ | ||
21 | static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) | ||
22 | { | ||
23 | const __be32 *bp = *_bp; | ||
24 | |||
25 | fid->vid = ntohl(*bp++); | ||
26 | fid->vnode = ntohl(*bp++); | ||
27 | fid->unique = ntohl(*bp++); | ||
28 | *_bp = bp; | ||
29 | } | ||
30 | |||
31 | /* | ||
19 | * decode an AFSFetchStatus block | 32 | * decode an AFSFetchStatus block |
20 | */ | 33 | */ |
21 | static void xdr_decode_AFSFetchStatus(const __be32 **_bp, | 34 | static void xdr_decode_AFSFetchStatus(const __be32 **_bp, |
35 | struct afs_file_status *status, | ||
22 | struct afs_vnode *vnode) | 36 | struct afs_vnode *vnode) |
23 | { | 37 | { |
24 | const __be32 *bp = *_bp; | 38 | const __be32 *bp = *_bp; |
25 | umode_t mode; | 39 | umode_t mode; |
26 | u64 data_version; | 40 | u64 data_version, size; |
27 | u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ | 41 | u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ |
28 | 42 | ||
29 | #define EXTRACT(DST) \ | 43 | #define EXTRACT(DST) \ |
@@ -33,55 +47,68 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp, | |||
33 | DST = x; \ | 47 | DST = x; \ |
34 | } while (0) | 48 | } while (0) |
35 | 49 | ||
36 | vnode->status.if_version = ntohl(*bp++); | 50 | status->if_version = ntohl(*bp++); |
37 | EXTRACT(vnode->status.type); | 51 | EXTRACT(status->type); |
38 | vnode->status.nlink = ntohl(*bp++); | 52 | EXTRACT(status->nlink); |
39 | EXTRACT(vnode->status.size); | 53 | size = ntohl(*bp++); |
40 | data_version = ntohl(*bp++); | 54 | data_version = ntohl(*bp++); |
41 | EXTRACT(vnode->status.author); | 55 | EXTRACT(status->author); |
42 | EXTRACT(vnode->status.owner); | 56 | EXTRACT(status->owner); |
43 | EXTRACT(vnode->status.caller_access); /* call ticket dependent */ | 57 | EXTRACT(status->caller_access); /* call ticket dependent */ |
44 | EXTRACT(vnode->status.anon_access); | 58 | EXTRACT(status->anon_access); |
45 | EXTRACT(vnode->status.mode); | 59 | EXTRACT(status->mode); |
46 | vnode->status.parent.vid = vnode->fid.vid; | 60 | EXTRACT(status->parent.vnode); |
47 | EXTRACT(vnode->status.parent.vnode); | 61 | EXTRACT(status->parent.unique); |
48 | EXTRACT(vnode->status.parent.unique); | ||
49 | bp++; /* seg size */ | 62 | bp++; /* seg size */ |
50 | vnode->status.mtime_client = ntohl(*bp++); | 63 | status->mtime_client = ntohl(*bp++); |
51 | vnode->status.mtime_server = ntohl(*bp++); | 64 | status->mtime_server = ntohl(*bp++); |
52 | bp++; /* group */ | 65 | EXTRACT(status->group); |
53 | bp++; /* sync counter */ | 66 | bp++; /* sync counter */ |
54 | data_version |= (u64) ntohl(*bp++) << 32; | 67 | data_version |= (u64) ntohl(*bp++) << 32; |
55 | bp++; /* spare2 */ | 68 | bp++; /* lock count */ |
56 | bp++; /* spare3 */ | 69 | size |= (u64) ntohl(*bp++) << 32; |
57 | bp++; /* spare4 */ | 70 | bp++; /* spare 4 */ |
58 | *_bp = bp; | 71 | *_bp = bp; |
59 | 72 | ||
60 | if (changed) { | 73 | if (size != status->size) { |
61 | _debug("vnode changed"); | 74 | status->size = size; |
62 | set_bit(AFS_VNODE_CHANGED, &vnode->flags); | 75 | changed |= true; |
63 | vnode->vfs_inode.i_uid = vnode->status.owner; | ||
64 | vnode->vfs_inode.i_size = vnode->status.size; | ||
65 | vnode->vfs_inode.i_version = vnode->fid.unique; | ||
66 | |||
67 | vnode->status.mode &= S_IALLUGO; | ||
68 | mode = vnode->vfs_inode.i_mode; | ||
69 | mode &= ~S_IALLUGO; | ||
70 | mode |= vnode->status.mode; | ||
71 | vnode->vfs_inode.i_mode = mode; | ||
72 | } | 76 | } |
77 | status->mode &= S_IALLUGO; | ||
73 | 78 | ||
74 | _debug("vnode time %lx, %lx", | 79 | _debug("vnode time %lx, %lx", |
75 | vnode->status.mtime_client, vnode->status.mtime_server); | 80 | status->mtime_client, status->mtime_server); |
76 | vnode->vfs_inode.i_ctime.tv_sec = vnode->status.mtime_server; | 81 | |
77 | vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; | 82 | if (vnode) { |
78 | vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; | 83 | status->parent.vid = vnode->fid.vid; |
79 | 84 | if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | |
80 | if (vnode->status.data_version != data_version) { | 85 | _debug("vnode changed"); |
81 | _debug("vnode modified %llx", data_version); | 86 | i_size_write(&vnode->vfs_inode, size); |
82 | vnode->status.data_version = data_version; | 87 | vnode->vfs_inode.i_uid = status->owner; |
83 | set_bit(AFS_VNODE_MODIFIED, &vnode->flags); | 88 | vnode->vfs_inode.i_gid = status->group; |
84 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); | 89 | vnode->vfs_inode.i_version = vnode->fid.unique; |
90 | vnode->vfs_inode.i_nlink = status->nlink; | ||
91 | |||
92 | mode = vnode->vfs_inode.i_mode; | ||
93 | mode &= ~S_IALLUGO; | ||
94 | mode |= status->mode; | ||
95 | barrier(); | ||
96 | vnode->vfs_inode.i_mode = mode; | ||
97 | } | ||
98 | |||
99 | vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server; | ||
100 | vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; | ||
101 | vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; | ||
102 | } | ||
103 | |||
104 | if (status->data_version != data_version) { | ||
105 | status->data_version = data_version; | ||
106 | if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | ||
107 | _debug("vnode modified %llx on {%x:%u}", | ||
108 | data_version, vnode->fid.vid, vnode->fid.vnode); | ||
109 | set_bit(AFS_VNODE_MODIFIED, &vnode->flags); | ||
110 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); | ||
111 | } | ||
85 | } | 112 | } |
86 | } | 113 | } |
87 | 114 | ||
@@ -99,6 +126,17 @@ static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode) | |||
99 | *_bp = bp; | 126 | *_bp = bp; |
100 | } | 127 | } |
101 | 128 | ||
129 | static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, | ||
130 | struct afs_callback *cb) | ||
131 | { | ||
132 | const __be32 *bp = *_bp; | ||
133 | |||
134 | cb->version = ntohl(*bp++); | ||
135 | cb->expiry = ntohl(*bp++); | ||
136 | cb->type = ntohl(*bp++); | ||
137 | *_bp = bp; | ||
138 | } | ||
139 | |||
102 | /* | 140 | /* |
103 | * decode an AFSVolSync block | 141 | * decode an AFSVolSync block |
104 | */ | 142 | */ |
@@ -122,6 +160,7 @@ static void xdr_decode_AFSVolSync(const __be32 **_bp, | |||
122 | static int afs_deliver_fs_fetch_status(struct afs_call *call, | 160 | static int afs_deliver_fs_fetch_status(struct afs_call *call, |
123 | struct sk_buff *skb, bool last) | 161 | struct sk_buff *skb, bool last) |
124 | { | 162 | { |
163 | struct afs_vnode *vnode = call->reply; | ||
125 | const __be32 *bp; | 164 | const __be32 *bp; |
126 | 165 | ||
127 | _enter(",,%u", last); | 166 | _enter(",,%u", last); |
@@ -135,8 +174,8 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call, | |||
135 | 174 | ||
136 | /* unmarshall the reply once we've received all of it */ | 175 | /* unmarshall the reply once we've received all of it */ |
137 | bp = call->buffer; | 176 | bp = call->buffer; |
138 | xdr_decode_AFSFetchStatus(&bp, call->reply); | 177 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); |
139 | xdr_decode_AFSCallBack(&bp, call->reply); | 178 | xdr_decode_AFSCallBack(&bp, vnode); |
140 | if (call->reply2) | 179 | if (call->reply2) |
141 | xdr_decode_AFSVolSync(&bp, call->reply2); | 180 | xdr_decode_AFSVolSync(&bp, call->reply2); |
142 | 181 | ||
@@ -166,9 +205,10 @@ int afs_fs_fetch_file_status(struct afs_server *server, | |||
166 | struct afs_call *call; | 205 | struct afs_call *call; |
167 | __be32 *bp; | 206 | __be32 *bp; |
168 | 207 | ||
169 | _enter(",%x,,,", key_serial(key)); | 208 | _enter(",%x,{%x:%d},,", |
209 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); | ||
170 | 210 | ||
171 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120); | 211 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); |
172 | if (!call) | 212 | if (!call) |
173 | return -ENOMEM; | 213 | return -ENOMEM; |
174 | 214 | ||
@@ -194,6 +234,7 @@ int afs_fs_fetch_file_status(struct afs_server *server, | |||
194 | static int afs_deliver_fs_fetch_data(struct afs_call *call, | 234 | static int afs_deliver_fs_fetch_data(struct afs_call *call, |
195 | struct sk_buff *skb, bool last) | 235 | struct sk_buff *skb, bool last) |
196 | { | 236 | { |
237 | struct afs_vnode *vnode = call->reply; | ||
197 | const __be32 *bp; | 238 | const __be32 *bp; |
198 | struct page *page; | 239 | struct page *page; |
199 | void *buffer; | 240 | void *buffer; |
@@ -248,7 +289,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, | |||
248 | 289 | ||
249 | /* extract the metadata */ | 290 | /* extract the metadata */ |
250 | case 3: | 291 | case 3: |
251 | ret = afs_extract_data(call, skb, last, call->buffer, 120); | 292 | ret = afs_extract_data(call, skb, last, call->buffer, |
293 | (21 + 3 + 6) * 4); | ||
252 | switch (ret) { | 294 | switch (ret) { |
253 | case 0: break; | 295 | case 0: break; |
254 | case -EAGAIN: return 0; | 296 | case -EAGAIN: return 0; |
@@ -256,8 +298,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, | |||
256 | } | 298 | } |
257 | 299 | ||
258 | bp = call->buffer; | 300 | bp = call->buffer; |
259 | xdr_decode_AFSFetchStatus(&bp, call->reply); | 301 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); |
260 | xdr_decode_AFSCallBack(&bp, call->reply); | 302 | xdr_decode_AFSCallBack(&bp, vnode); |
261 | if (call->reply2) | 303 | if (call->reply2) |
262 | xdr_decode_AFSVolSync(&bp, call->reply2); | 304 | xdr_decode_AFSVolSync(&bp, call->reply2); |
263 | 305 | ||
@@ -296,7 +338,6 @@ int afs_fs_fetch_data(struct afs_server *server, | |||
296 | struct afs_vnode *vnode, | 338 | struct afs_vnode *vnode, |
297 | off_t offset, size_t length, | 339 | off_t offset, size_t length, |
298 | struct page *buffer, | 340 | struct page *buffer, |
299 | struct afs_volsync *volsync, | ||
300 | const struct afs_wait_mode *wait_mode) | 341 | const struct afs_wait_mode *wait_mode) |
301 | { | 342 | { |
302 | struct afs_call *call; | 343 | struct afs_call *call; |
@@ -304,13 +345,13 @@ int afs_fs_fetch_data(struct afs_server *server, | |||
304 | 345 | ||
305 | _enter(""); | 346 | _enter(""); |
306 | 347 | ||
307 | call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, 120); | 348 | call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); |
308 | if (!call) | 349 | if (!call) |
309 | return -ENOMEM; | 350 | return -ENOMEM; |
310 | 351 | ||
311 | call->key = key; | 352 | call->key = key; |
312 | call->reply = vnode; | 353 | call->reply = vnode; |
313 | call->reply2 = volsync; | 354 | call->reply2 = NULL; /* volsync */ |
314 | call->reply3 = buffer; | 355 | call->reply3 = buffer; |
315 | call->service_id = FS_SERVICE; | 356 | call->service_id = FS_SERVICE; |
316 | call->port = htons(AFS_FS_PORT); | 357 | call->port = htons(AFS_FS_PORT); |
@@ -411,3 +452,485 @@ int afs_fs_give_up_callbacks(struct afs_server *server, | |||
411 | 452 | ||
412 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 453 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
413 | } | 454 | } |
455 | |||
456 | /* | ||
457 | * deliver reply data to an FS.CreateFile or an FS.MakeDir | ||
458 | */ | ||
459 | static int afs_deliver_fs_create_vnode(struct afs_call *call, | ||
460 | struct sk_buff *skb, bool last) | ||
461 | { | ||
462 | struct afs_vnode *vnode = call->reply; | ||
463 | const __be32 *bp; | ||
464 | |||
465 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | ||
466 | |||
467 | afs_transfer_reply(call, skb); | ||
468 | if (!last) | ||
469 | return 0; | ||
470 | |||
471 | if (call->reply_size != call->reply_max) | ||
472 | return -EBADMSG; | ||
473 | |||
474 | /* unmarshall the reply once we've received all of it */ | ||
475 | bp = call->buffer; | ||
476 | xdr_decode_AFSFid(&bp, call->reply2); | ||
477 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); | ||
478 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | ||
479 | xdr_decode_AFSCallBack_raw(&bp, call->reply4); | ||
480 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
481 | |||
482 | _leave(" = 0 [done]"); | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | /* | ||
487 | * FS.CreateFile and FS.MakeDir operation type | ||
488 | */ | ||
489 | static const struct afs_call_type afs_RXFSCreateXXXX = { | ||
490 | .name = "FS.CreateXXXX", | ||
491 | .deliver = afs_deliver_fs_create_vnode, | ||
492 | .abort_to_error = afs_abort_to_error, | ||
493 | .destructor = afs_flat_call_destructor, | ||
494 | }; | ||
495 | |||
496 | /* | ||
497 | * create a file or make a directory | ||
498 | */ | ||
499 | int afs_fs_create(struct afs_server *server, | ||
500 | struct key *key, | ||
501 | struct afs_vnode *vnode, | ||
502 | const char *name, | ||
503 | umode_t mode, | ||
504 | struct afs_fid *newfid, | ||
505 | struct afs_file_status *newstatus, | ||
506 | struct afs_callback *newcb, | ||
507 | const struct afs_wait_mode *wait_mode) | ||
508 | { | ||
509 | struct afs_call *call; | ||
510 | size_t namesz, reqsz, padsz; | ||
511 | __be32 *bp; | ||
512 | |||
513 | _enter(""); | ||
514 | |||
515 | namesz = strlen(name); | ||
516 | padsz = (4 - (namesz & 3)) & 3; | ||
517 | reqsz = (5 * 4) + namesz + padsz + (6 * 4); | ||
518 | |||
519 | call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz, | ||
520 | (3 + 21 + 21 + 3 + 6) * 4); | ||
521 | if (!call) | ||
522 | return -ENOMEM; | ||
523 | |||
524 | call->key = key; | ||
525 | call->reply = vnode; | ||
526 | call->reply2 = newfid; | ||
527 | call->reply3 = newstatus; | ||
528 | call->reply4 = newcb; | ||
529 | call->service_id = FS_SERVICE; | ||
530 | call->port = htons(AFS_FS_PORT); | ||
531 | |||
532 | /* marshall the parameters */ | ||
533 | bp = call->request; | ||
534 | *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); | ||
535 | *bp++ = htonl(vnode->fid.vid); | ||
536 | *bp++ = htonl(vnode->fid.vnode); | ||
537 | *bp++ = htonl(vnode->fid.unique); | ||
538 | *bp++ = htonl(namesz); | ||
539 | memcpy(bp, name, namesz); | ||
540 | bp = (void *) bp + namesz; | ||
541 | if (padsz > 0) { | ||
542 | memset(bp, 0, padsz); | ||
543 | bp = (void *) bp + padsz; | ||
544 | } | ||
545 | *bp++ = htonl(AFS_SET_MODE); | ||
546 | *bp++ = 0; /* mtime */ | ||
547 | *bp++ = 0; /* owner */ | ||
548 | *bp++ = 0; /* group */ | ||
549 | *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ | ||
550 | *bp++ = 0; /* segment size */ | ||
551 | |||
552 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
553 | } | ||
554 | |||
555 | /* | ||
556 | * deliver reply data to an FS.RemoveFile or FS.RemoveDir | ||
557 | */ | ||
558 | static int afs_deliver_fs_remove(struct afs_call *call, | ||
559 | struct sk_buff *skb, bool last) | ||
560 | { | ||
561 | struct afs_vnode *vnode = call->reply; | ||
562 | const __be32 *bp; | ||
563 | |||
564 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | ||
565 | |||
566 | afs_transfer_reply(call, skb); | ||
567 | if (!last) | ||
568 | return 0; | ||
569 | |||
570 | if (call->reply_size != call->reply_max) | ||
571 | return -EBADMSG; | ||
572 | |||
573 | /* unmarshall the reply once we've received all of it */ | ||
574 | bp = call->buffer; | ||
575 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | ||
576 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
577 | |||
578 | _leave(" = 0 [done]"); | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | * FS.RemoveDir/FS.RemoveFile operation type | ||
584 | */ | ||
585 | static const struct afs_call_type afs_RXFSRemoveXXXX = { | ||
586 | .name = "FS.RemoveXXXX", | ||
587 | .deliver = afs_deliver_fs_remove, | ||
588 | .abort_to_error = afs_abort_to_error, | ||
589 | .destructor = afs_flat_call_destructor, | ||
590 | }; | ||
591 | |||
592 | /* | ||
593 | * remove a file or directory | ||
594 | */ | ||
595 | int afs_fs_remove(struct afs_server *server, | ||
596 | struct key *key, | ||
597 | struct afs_vnode *vnode, | ||
598 | const char *name, | ||
599 | bool isdir, | ||
600 | const struct afs_wait_mode *wait_mode) | ||
601 | { | ||
602 | struct afs_call *call; | ||
603 | size_t namesz, reqsz, padsz; | ||
604 | __be32 *bp; | ||
605 | |||
606 | _enter(""); | ||
607 | |||
608 | namesz = strlen(name); | ||
609 | padsz = (4 - (namesz & 3)) & 3; | ||
610 | reqsz = (5 * 4) + namesz + padsz; | ||
611 | |||
612 | call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4); | ||
613 | if (!call) | ||
614 | return -ENOMEM; | ||
615 | |||
616 | call->key = key; | ||
617 | call->reply = vnode; | ||
618 | call->service_id = FS_SERVICE; | ||
619 | call->port = htons(AFS_FS_PORT); | ||
620 | |||
621 | /* marshall the parameters */ | ||
622 | bp = call->request; | ||
623 | *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); | ||
624 | *bp++ = htonl(vnode->fid.vid); | ||
625 | *bp++ = htonl(vnode->fid.vnode); | ||
626 | *bp++ = htonl(vnode->fid.unique); | ||
627 | *bp++ = htonl(namesz); | ||
628 | memcpy(bp, name, namesz); | ||
629 | bp = (void *) bp + namesz; | ||
630 | if (padsz > 0) { | ||
631 | memset(bp, 0, padsz); | ||
632 | bp = (void *) bp + padsz; | ||
633 | } | ||
634 | |||
635 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
636 | } | ||
637 | |||
638 | /* | ||
639 | * deliver reply data to an FS.Link | ||
640 | */ | ||
641 | static int afs_deliver_fs_link(struct afs_call *call, | ||
642 | struct sk_buff *skb, bool last) | ||
643 | { | ||
644 | struct afs_vnode *dvnode = call->reply, *vnode = call->reply2; | ||
645 | const __be32 *bp; | ||
646 | |||
647 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | ||
648 | |||
649 | afs_transfer_reply(call, skb); | ||
650 | if (!last) | ||
651 | return 0; | ||
652 | |||
653 | if (call->reply_size != call->reply_max) | ||
654 | return -EBADMSG; | ||
655 | |||
656 | /* unmarshall the reply once we've received all of it */ | ||
657 | bp = call->buffer; | ||
658 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | ||
659 | xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode); | ||
660 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
661 | |||
662 | _leave(" = 0 [done]"); | ||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | /* | ||
667 | * FS.Link operation type | ||
668 | */ | ||
669 | static const struct afs_call_type afs_RXFSLink = { | ||
670 | .name = "FS.Link", | ||
671 | .deliver = afs_deliver_fs_link, | ||
672 | .abort_to_error = afs_abort_to_error, | ||
673 | .destructor = afs_flat_call_destructor, | ||
674 | }; | ||
675 | |||
676 | /* | ||
677 | * make a hard link | ||
678 | */ | ||
679 | int afs_fs_link(struct afs_server *server, | ||
680 | struct key *key, | ||
681 | struct afs_vnode *dvnode, | ||
682 | struct afs_vnode *vnode, | ||
683 | const char *name, | ||
684 | const struct afs_wait_mode *wait_mode) | ||
685 | { | ||
686 | struct afs_call *call; | ||
687 | size_t namesz, reqsz, padsz; | ||
688 | __be32 *bp; | ||
689 | |||
690 | _enter(""); | ||
691 | |||
692 | namesz = strlen(name); | ||
693 | padsz = (4 - (namesz & 3)) & 3; | ||
694 | reqsz = (5 * 4) + namesz + padsz + (3 * 4); | ||
695 | |||
696 | call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); | ||
697 | if (!call) | ||
698 | return -ENOMEM; | ||
699 | |||
700 | call->key = key; | ||
701 | call->reply = dvnode; | ||
702 | call->reply2 = vnode; | ||
703 | call->service_id = FS_SERVICE; | ||
704 | call->port = htons(AFS_FS_PORT); | ||
705 | |||
706 | /* marshall the parameters */ | ||
707 | bp = call->request; | ||
708 | *bp++ = htonl(FSLINK); | ||
709 | *bp++ = htonl(dvnode->fid.vid); | ||
710 | *bp++ = htonl(dvnode->fid.vnode); | ||
711 | *bp++ = htonl(dvnode->fid.unique); | ||
712 | *bp++ = htonl(namesz); | ||
713 | memcpy(bp, name, namesz); | ||
714 | bp = (void *) bp + namesz; | ||
715 | if (padsz > 0) { | ||
716 | memset(bp, 0, padsz); | ||
717 | bp = (void *) bp + padsz; | ||
718 | } | ||
719 | *bp++ = htonl(vnode->fid.vid); | ||
720 | *bp++ = htonl(vnode->fid.vnode); | ||
721 | *bp++ = htonl(vnode->fid.unique); | ||
722 | |||
723 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
724 | } | ||
725 | |||
726 | /* | ||
727 | * deliver reply data to an FS.Symlink | ||
728 | */ | ||
729 | static int afs_deliver_fs_symlink(struct afs_call *call, | ||
730 | struct sk_buff *skb, bool last) | ||
731 | { | ||
732 | struct afs_vnode *vnode = call->reply; | ||
733 | const __be32 *bp; | ||
734 | |||
735 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | ||
736 | |||
737 | afs_transfer_reply(call, skb); | ||
738 | if (!last) | ||
739 | return 0; | ||
740 | |||
741 | if (call->reply_size != call->reply_max) | ||
742 | return -EBADMSG; | ||
743 | |||
744 | /* unmarshall the reply once we've received all of it */ | ||
745 | bp = call->buffer; | ||
746 | xdr_decode_AFSFid(&bp, call->reply2); | ||
747 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); | ||
748 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | ||
749 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
750 | |||
751 | _leave(" = 0 [done]"); | ||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | /* | ||
756 | * FS.Symlink operation type | ||
757 | */ | ||
758 | static const struct afs_call_type afs_RXFSSymlink = { | ||
759 | .name = "FS.Symlink", | ||
760 | .deliver = afs_deliver_fs_symlink, | ||
761 | .abort_to_error = afs_abort_to_error, | ||
762 | .destructor = afs_flat_call_destructor, | ||
763 | }; | ||
764 | |||
765 | /* | ||
766 | * create a symbolic link | ||
767 | */ | ||
768 | int afs_fs_symlink(struct afs_server *server, | ||
769 | struct key *key, | ||
770 | struct afs_vnode *vnode, | ||
771 | const char *name, | ||
772 | const char *contents, | ||
773 | struct afs_fid *newfid, | ||
774 | struct afs_file_status *newstatus, | ||
775 | const struct afs_wait_mode *wait_mode) | ||
776 | { | ||
777 | struct afs_call *call; | ||
778 | size_t namesz, reqsz, padsz, c_namesz, c_padsz; | ||
779 | __be32 *bp; | ||
780 | |||
781 | _enter(""); | ||
782 | |||
783 | namesz = strlen(name); | ||
784 | padsz = (4 - (namesz & 3)) & 3; | ||
785 | |||
786 | c_namesz = strlen(contents); | ||
787 | c_padsz = (4 - (c_namesz & 3)) & 3; | ||
788 | |||
789 | reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); | ||
790 | |||
791 | call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz, | ||
792 | (3 + 21 + 21 + 6) * 4); | ||
793 | if (!call) | ||
794 | return -ENOMEM; | ||
795 | |||
796 | call->key = key; | ||
797 | call->reply = vnode; | ||
798 | call->reply2 = newfid; | ||
799 | call->reply3 = newstatus; | ||
800 | call->service_id = FS_SERVICE; | ||
801 | call->port = htons(AFS_FS_PORT); | ||
802 | |||
803 | /* marshall the parameters */ | ||
804 | bp = call->request; | ||
805 | *bp++ = htonl(FSSYMLINK); | ||
806 | *bp++ = htonl(vnode->fid.vid); | ||
807 | *bp++ = htonl(vnode->fid.vnode); | ||
808 | *bp++ = htonl(vnode->fid.unique); | ||
809 | *bp++ = htonl(namesz); | ||
810 | memcpy(bp, name, namesz); | ||
811 | bp = (void *) bp + namesz; | ||
812 | if (padsz > 0) { | ||
813 | memset(bp, 0, padsz); | ||
814 | bp = (void *) bp + padsz; | ||
815 | } | ||
816 | *bp++ = htonl(c_namesz); | ||
817 | memcpy(bp, contents, c_namesz); | ||
818 | bp = (void *) bp + c_namesz; | ||
819 | if (c_padsz > 0) { | ||
820 | memset(bp, 0, c_padsz); | ||
821 | bp = (void *) bp + c_padsz; | ||
822 | } | ||
823 | *bp++ = htonl(AFS_SET_MODE); | ||
824 | *bp++ = 0; /* mtime */ | ||
825 | *bp++ = 0; /* owner */ | ||
826 | *bp++ = 0; /* group */ | ||
827 | *bp++ = htonl(S_IRWXUGO); /* unix mode */ | ||
828 | *bp++ = 0; /* segment size */ | ||
829 | |||
830 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
831 | } | ||
832 | |||
833 | /* | ||
834 | * deliver reply data to an FS.Rename | ||
835 | */ | ||
836 | static int afs_deliver_fs_rename(struct afs_call *call, | ||
837 | struct sk_buff *skb, bool last) | ||
838 | { | ||
839 | struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2; | ||
840 | const __be32 *bp; | ||
841 | |||
842 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | ||
843 | |||
844 | afs_transfer_reply(call, skb); | ||
845 | if (!last) | ||
846 | return 0; | ||
847 | |||
848 | if (call->reply_size != call->reply_max) | ||
849 | return -EBADMSG; | ||
850 | |||
851 | /* unmarshall the reply once we've received all of it */ | ||
852 | bp = call->buffer; | ||
853 | xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode); | ||
854 | if (new_dvnode != orig_dvnode) | ||
855 | xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode); | ||
856 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
857 | |||
858 | _leave(" = 0 [done]"); | ||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | /* | ||
863 | * FS.Rename operation type | ||
864 | */ | ||
865 | static const struct afs_call_type afs_RXFSRename = { | ||
866 | .name = "FS.Rename", | ||
867 | .deliver = afs_deliver_fs_rename, | ||
868 | .abort_to_error = afs_abort_to_error, | ||
869 | .destructor = afs_flat_call_destructor, | ||
870 | }; | ||
871 | |||
872 | /* | ||
873 | * create a symbolic link | ||
874 | */ | ||
875 | int afs_fs_rename(struct afs_server *server, | ||
876 | struct key *key, | ||
877 | struct afs_vnode *orig_dvnode, | ||
878 | const char *orig_name, | ||
879 | struct afs_vnode *new_dvnode, | ||
880 | const char *new_name, | ||
881 | const struct afs_wait_mode *wait_mode) | ||
882 | { | ||
883 | struct afs_call *call; | ||
884 | size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; | ||
885 | __be32 *bp; | ||
886 | |||
887 | _enter(""); | ||
888 | |||
889 | o_namesz = strlen(orig_name); | ||
890 | o_padsz = (4 - (o_namesz & 3)) & 3; | ||
891 | |||
892 | n_namesz = strlen(new_name); | ||
893 | n_padsz = (4 - (n_namesz & 3)) & 3; | ||
894 | |||
895 | reqsz = (4 * 4) + | ||
896 | 4 + o_namesz + o_padsz + | ||
897 | (3 * 4) + | ||
898 | 4 + n_namesz + n_padsz; | ||
899 | |||
900 | call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); | ||
901 | if (!call) | ||
902 | return -ENOMEM; | ||
903 | |||
904 | call->key = key; | ||
905 | call->reply = orig_dvnode; | ||
906 | call->reply2 = new_dvnode; | ||
907 | call->service_id = FS_SERVICE; | ||
908 | call->port = htons(AFS_FS_PORT); | ||
909 | |||
910 | /* marshall the parameters */ | ||
911 | bp = call->request; | ||
912 | *bp++ = htonl(FSRENAME); | ||
913 | *bp++ = htonl(orig_dvnode->fid.vid); | ||
914 | *bp++ = htonl(orig_dvnode->fid.vnode); | ||
915 | *bp++ = htonl(orig_dvnode->fid.unique); | ||
916 | *bp++ = htonl(o_namesz); | ||
917 | memcpy(bp, orig_name, o_namesz); | ||
918 | bp = (void *) bp + o_namesz; | ||
919 | if (o_padsz > 0) { | ||
920 | memset(bp, 0, o_padsz); | ||
921 | bp = (void *) bp + o_padsz; | ||
922 | } | ||
923 | |||
924 | *bp++ = htonl(new_dvnode->fid.vid); | ||
925 | *bp++ = htonl(new_dvnode->fid.vnode); | ||
926 | *bp++ = htonl(new_dvnode->fid.unique); | ||
927 | *bp++ = htonl(n_namesz); | ||
928 | memcpy(bp, new_name, n_namesz); | ||
929 | bp = (void *) bp + n_namesz; | ||
930 | if (n_padsz > 0) { | ||
931 | memset(bp, 0, n_padsz); | ||
932 | bp = (void *) bp + n_padsz; | ||
933 | } | ||
934 | |||
935 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
936 | } | ||