aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs/fsclient.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2007-04-26 18:59:35 -0400
committerDavid S. Miller <davem@davemloft.net>2007-04-26 18:59:35 -0400
commit260a980317dac80182dd76140cf67c6e81d6d3dd (patch)
tree84f3e919fd33be56aad4fc57f5cb844df1a6b952 /fs/afs/fsclient.c
parentc35eccb1f614954b10cba3f74b7c301993b2f42e (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.c625
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 */
21static 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 */
21static void xdr_decode_AFSFetchStatus(const __be32 **_bp, 34static 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
129static 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,
122static int afs_deliver_fs_fetch_status(struct afs_call *call, 160static 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,
194static int afs_deliver_fs_fetch_data(struct afs_call *call, 234static 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 */
459static 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 */
489static 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 */
499int 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 */
558static 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 */
585static 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 */
595int 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 */
641static 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 */
669static 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 */
679int 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 */
729static 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 */
758static 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 */
768int 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 */
836static 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 */
865static 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 */
875int 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}