[AFS]: Eliminate cmpxchg() usage in vlocation code.
[linux-2.6] / fs / afs / fsclient.c
1 /* AFS File Server client stubs
2  *
3  * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
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>
13 #include <linux/sched.h>
14 #include <linux/circ_buf.h>
15 #include "internal.h"
16 #include "afs_fs.h"
17
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 /*
32  * decode an AFSFetchStatus block
33  */
34 static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
35                                       struct afs_file_status *status,
36                                       struct afs_vnode *vnode)
37 {
38         const __be32 *bp = *_bp;
39         umode_t mode;
40         u64 data_version, size;
41         u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
42
43 #define EXTRACT(DST)                            \
44         do {                                    \
45                 u32 x = ntohl(*bp++);           \
46                 changed |= DST - x;             \
47                 DST = x;                        \
48         } while (0)
49
50         status->if_version = ntohl(*bp++);
51         EXTRACT(status->type);
52         EXTRACT(status->nlink);
53         size = ntohl(*bp++);
54         data_version = ntohl(*bp++);
55         EXTRACT(status->author);
56         EXTRACT(status->owner);
57         EXTRACT(status->caller_access); /* call ticket dependent */
58         EXTRACT(status->anon_access);
59         EXTRACT(status->mode);
60         EXTRACT(status->parent.vnode);
61         EXTRACT(status->parent.unique);
62         bp++; /* seg size */
63         status->mtime_client = ntohl(*bp++);
64         status->mtime_server = ntohl(*bp++);
65         EXTRACT(status->group);
66         bp++; /* sync counter */
67         data_version |= (u64) ntohl(*bp++) << 32;
68         bp++; /* lock count */
69         size |= (u64) ntohl(*bp++) << 32;
70         bp++; /* spare 4 */
71         *_bp = bp;
72
73         if (size != status->size) {
74                 status->size = size;
75                 changed |= true;
76         }
77         status->mode &= S_IALLUGO;
78
79         _debug("vnode time %lx, %lx",
80                status->mtime_client, status->mtime_server);
81
82         if (vnode) {
83                 status->parent.vid = vnode->fid.vid;
84                 if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
85                         _debug("vnode changed");
86                         i_size_write(&vnode->vfs_inode, size);
87                         vnode->vfs_inode.i_uid = status->owner;
88                         vnode->vfs_inode.i_gid = status->group;
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                                (unsigned long long) data_version,
109                                vnode->fid.vid, vnode->fid.vnode);
110                         set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
111                         set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
112                 }
113         }
114 }
115
116 /*
117  * decode an AFSCallBack block
118  */
119 static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
120 {
121         const __be32 *bp = *_bp;
122
123         vnode->cb_version       = ntohl(*bp++);
124         vnode->cb_expiry        = ntohl(*bp++);
125         vnode->cb_type          = ntohl(*bp++);
126         vnode->cb_expires       = vnode->cb_expiry + get_seconds();
127         *_bp = bp;
128 }
129
130 static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
131                                        struct afs_callback *cb)
132 {
133         const __be32 *bp = *_bp;
134
135         cb->version     = ntohl(*bp++);
136         cb->expiry      = ntohl(*bp++);
137         cb->type        = ntohl(*bp++);
138         *_bp = bp;
139 }
140
141 /*
142  * decode an AFSVolSync block
143  */
144 static void xdr_decode_AFSVolSync(const __be32 **_bp,
145                                   struct afs_volsync *volsync)
146 {
147         const __be32 *bp = *_bp;
148
149         volsync->creation = ntohl(*bp++);
150         bp++; /* spare2 */
151         bp++; /* spare3 */
152         bp++; /* spare4 */
153         bp++; /* spare5 */
154         bp++; /* spare6 */
155         *_bp = bp;
156 }
157
158 /*
159  * deliver reply data to an FS.FetchStatus
160  */
161 static int afs_deliver_fs_fetch_status(struct afs_call *call,
162                                        struct sk_buff *skb, bool last)
163 {
164         struct afs_vnode *vnode = call->reply;
165         const __be32 *bp;
166
167         _enter(",,%u", last);
168
169         afs_transfer_reply(call, skb);
170         if (!last)
171                 return 0;
172
173         if (call->reply_size != call->reply_max)
174                 return -EBADMSG;
175
176         /* unmarshall the reply once we've received all of it */
177         bp = call->buffer;
178         xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
179         xdr_decode_AFSCallBack(&bp, vnode);
180         if (call->reply2)
181                 xdr_decode_AFSVolSync(&bp, call->reply2);
182
183         _leave(" = 0 [done]");
184         return 0;
185 }
186
187 /*
188  * FS.FetchStatus operation type
189  */
190 static const struct afs_call_type afs_RXFSFetchStatus = {
191         .name           = "FS.FetchStatus",
192         .deliver        = afs_deliver_fs_fetch_status,
193         .abort_to_error = afs_abort_to_error,
194         .destructor     = afs_flat_call_destructor,
195 };
196
197 /*
198  * fetch the status information for a file
199  */
200 int afs_fs_fetch_file_status(struct afs_server *server,
201                              struct key *key,
202                              struct afs_vnode *vnode,
203                              struct afs_volsync *volsync,
204                              const struct afs_wait_mode *wait_mode)
205 {
206         struct afs_call *call;
207         __be32 *bp;
208
209         _enter(",%x,{%x:%d},,",
210                key_serial(key), vnode->fid.vid, vnode->fid.vnode);
211
212         call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
213         if (!call)
214                 return -ENOMEM;
215
216         call->key = key;
217         call->reply = vnode;
218         call->reply2 = volsync;
219         call->service_id = FS_SERVICE;
220         call->port = htons(AFS_FS_PORT);
221
222         /* marshall the parameters */
223         bp = call->request;
224         bp[0] = htonl(FSFETCHSTATUS);
225         bp[1] = htonl(vnode->fid.vid);
226         bp[2] = htonl(vnode->fid.vnode);
227         bp[3] = htonl(vnode->fid.unique);
228
229         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
230 }
231
232 /*
233  * deliver reply data to an FS.FetchData
234  */
235 static int afs_deliver_fs_fetch_data(struct afs_call *call,
236                                      struct sk_buff *skb, bool last)
237 {
238         struct afs_vnode *vnode = call->reply;
239         const __be32 *bp;
240         struct page *page;
241         void *buffer;
242         int ret;
243
244         _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
245
246         switch (call->unmarshall) {
247         case 0:
248                 call->offset = 0;
249                 call->unmarshall++;
250
251                 /* extract the returned data length */
252         case 1:
253                 _debug("extract data length");
254                 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
255                 switch (ret) {
256                 case 0:         break;
257                 case -EAGAIN:   return 0;
258                 default:        return ret;
259                 }
260
261                 call->count = ntohl(call->tmp);
262                 _debug("DATA length: %u", call->count);
263                 if (call->count > PAGE_SIZE)
264                         return -EBADMSG;
265                 call->offset = 0;
266                 call->unmarshall++;
267
268                 if (call->count < PAGE_SIZE) {
269                         buffer = kmap_atomic(call->reply3, KM_USER0);
270                         memset(buffer + PAGE_SIZE - call->count, 0,
271                                call->count);
272                         kunmap_atomic(buffer, KM_USER0);
273                 }
274
275                 /* extract the returned data */
276         case 2:
277                 _debug("extract data");
278                 page = call->reply3;
279                 buffer = kmap_atomic(page, KM_USER0);
280                 ret = afs_extract_data(call, skb, last, buffer, call->count);
281                 kunmap_atomic(buffer, KM_USER0);
282                 switch (ret) {
283                 case 0:         break;
284                 case -EAGAIN:   return 0;
285                 default:        return ret;
286                 }
287
288                 call->offset = 0;
289                 call->unmarshall++;
290
291                 /* extract the metadata */
292         case 3:
293                 ret = afs_extract_data(call, skb, last, call->buffer,
294                                        (21 + 3 + 6) * 4);
295                 switch (ret) {
296                 case 0:         break;
297                 case -EAGAIN:   return 0;
298                 default:        return ret;
299                 }
300
301                 bp = call->buffer;
302                 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
303                 xdr_decode_AFSCallBack(&bp, vnode);
304                 if (call->reply2)
305                         xdr_decode_AFSVolSync(&bp, call->reply2);
306
307                 call->offset = 0;
308                 call->unmarshall++;
309
310         case 4:
311                 _debug("trailer");
312                 if (skb->len != 0)
313                         return -EBADMSG;
314                 break;
315         }
316
317         if (!last)
318                 return 0;
319
320         _leave(" = 0 [done]");
321         return 0;
322 }
323
324 /*
325  * FS.FetchData operation type
326  */
327 static const struct afs_call_type afs_RXFSFetchData = {
328         .name           = "FS.FetchData",
329         .deliver        = afs_deliver_fs_fetch_data,
330         .abort_to_error = afs_abort_to_error,
331         .destructor     = afs_flat_call_destructor,
332 };
333
334 /*
335  * fetch data from a file
336  */
337 int afs_fs_fetch_data(struct afs_server *server,
338                       struct key *key,
339                       struct afs_vnode *vnode,
340                       off_t offset, size_t length,
341                       struct page *buffer,
342                       const struct afs_wait_mode *wait_mode)
343 {
344         struct afs_call *call;
345         __be32 *bp;
346
347         _enter("");
348
349         call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
350         if (!call)
351                 return -ENOMEM;
352
353         call->key = key;
354         call->reply = vnode;
355         call->reply2 = NULL; /* volsync */
356         call->reply3 = buffer;
357         call->service_id = FS_SERVICE;
358         call->port = htons(AFS_FS_PORT);
359
360         /* marshall the parameters */
361         bp = call->request;
362         bp[0] = htonl(FSFETCHDATA);
363         bp[1] = htonl(vnode->fid.vid);
364         bp[2] = htonl(vnode->fid.vnode);
365         bp[3] = htonl(vnode->fid.unique);
366         bp[4] = htonl(offset);
367         bp[5] = htonl(length);
368
369         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
370 }
371
372 /*
373  * deliver reply data to an FS.GiveUpCallBacks
374  */
375 static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
376                                             struct sk_buff *skb, bool last)
377 {
378         _enter(",{%u},%d", skb->len, last);
379
380         if (skb->len > 0)
381                 return -EBADMSG; /* shouldn't be any reply data */
382         return 0;
383 }
384
385 /*
386  * FS.GiveUpCallBacks operation type
387  */
388 static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
389         .name           = "FS.GiveUpCallBacks",
390         .deliver        = afs_deliver_fs_give_up_callbacks,
391         .abort_to_error = afs_abort_to_error,
392         .destructor     = afs_flat_call_destructor,
393 };
394
395 /*
396  * give up a set of callbacks
397  * - the callbacks are held in the server->cb_break ring
398  */
399 int afs_fs_give_up_callbacks(struct afs_server *server,
400                              const struct afs_wait_mode *wait_mode)
401 {
402         struct afs_call *call;
403         size_t ncallbacks;
404         __be32 *bp, *tp;
405         int loop;
406
407         ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
408                               ARRAY_SIZE(server->cb_break));
409
410         _enter("{%zu},", ncallbacks);
411
412         if (ncallbacks == 0)
413                 return 0;
414         if (ncallbacks > AFSCBMAX)
415                 ncallbacks = AFSCBMAX;
416
417         _debug("break %zu callbacks", ncallbacks);
418
419         call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
420                                    12 + ncallbacks * 6 * 4, 0);
421         if (!call)
422                 return -ENOMEM;
423
424         call->service_id = FS_SERVICE;
425         call->port = htons(AFS_FS_PORT);
426
427         /* marshall the parameters */
428         bp = call->request;
429         tp = bp + 2 + ncallbacks * 3;
430         *bp++ = htonl(FSGIVEUPCALLBACKS);
431         *bp++ = htonl(ncallbacks);
432         *tp++ = htonl(ncallbacks);
433
434         atomic_sub(ncallbacks, &server->cb_break_n);
435         for (loop = ncallbacks; loop > 0; loop--) {
436                 struct afs_callback *cb =
437                         &server->cb_break[server->cb_break_tail];
438
439                 *bp++ = htonl(cb->fid.vid);
440                 *bp++ = htonl(cb->fid.vnode);
441                 *bp++ = htonl(cb->fid.unique);
442                 *tp++ = htonl(cb->version);
443                 *tp++ = htonl(cb->expiry);
444                 *tp++ = htonl(cb->type);
445                 smp_mb();
446                 server->cb_break_tail =
447                         (server->cb_break_tail + 1) &
448                         (ARRAY_SIZE(server->cb_break) - 1);
449         }
450
451         ASSERT(ncallbacks > 0);
452         wake_up_nr(&server->cb_break_waitq, ncallbacks);
453
454         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
455 }
456
457 /*
458  * deliver reply data to an FS.CreateFile or an FS.MakeDir
459  */
460 static int afs_deliver_fs_create_vnode(struct afs_call *call,
461                                        struct sk_buff *skb, bool last)
462 {
463         struct afs_vnode *vnode = call->reply;
464         const __be32 *bp;
465
466         _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
467
468         afs_transfer_reply(call, skb);
469         if (!last)
470                 return 0;
471
472         if (call->reply_size != call->reply_max)
473                 return -EBADMSG;
474
475         /* unmarshall the reply once we've received all of it */
476         bp = call->buffer;
477         xdr_decode_AFSFid(&bp, call->reply2);
478         xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
479         xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
480         xdr_decode_AFSCallBack_raw(&bp, call->reply4);
481         /* xdr_decode_AFSVolSync(&bp, call->replyX); */
482
483         _leave(" = 0 [done]");
484         return 0;
485 }
486
487 /*
488  * FS.CreateFile and FS.MakeDir operation type
489  */
490 static const struct afs_call_type afs_RXFSCreateXXXX = {
491         .name           = "FS.CreateXXXX",
492         .deliver        = afs_deliver_fs_create_vnode,
493         .abort_to_error = afs_abort_to_error,
494         .destructor     = afs_flat_call_destructor,
495 };
496
497 /*
498  * create a file or make a directory
499  */
500 int afs_fs_create(struct afs_server *server,
501                   struct key *key,
502                   struct afs_vnode *vnode,
503                   const char *name,
504                   umode_t mode,
505                   struct afs_fid *newfid,
506                   struct afs_file_status *newstatus,
507                   struct afs_callback *newcb,
508                   const struct afs_wait_mode *wait_mode)
509 {
510         struct afs_call *call;
511         size_t namesz, reqsz, padsz;
512         __be32 *bp;
513
514         _enter("");
515
516         namesz = strlen(name);
517         padsz = (4 - (namesz & 3)) & 3;
518         reqsz = (5 * 4) + namesz + padsz + (6 * 4);
519
520         call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
521                                    (3 + 21 + 21 + 3 + 6) * 4);
522         if (!call)
523                 return -ENOMEM;
524
525         call->key = key;
526         call->reply = vnode;
527         call->reply2 = newfid;
528         call->reply3 = newstatus;
529         call->reply4 = newcb;
530         call->service_id = FS_SERVICE;
531         call->port = htons(AFS_FS_PORT);
532
533         /* marshall the parameters */
534         bp = call->request;
535         *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
536         *bp++ = htonl(vnode->fid.vid);
537         *bp++ = htonl(vnode->fid.vnode);
538         *bp++ = htonl(vnode->fid.unique);
539         *bp++ = htonl(namesz);
540         memcpy(bp, name, namesz);
541         bp = (void *) bp + namesz;
542         if (padsz > 0) {
543                 memset(bp, 0, padsz);
544                 bp = (void *) bp + padsz;
545         }
546         *bp++ = htonl(AFS_SET_MODE);
547         *bp++ = 0; /* mtime */
548         *bp++ = 0; /* owner */
549         *bp++ = 0; /* group */
550         *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
551         *bp++ = 0; /* segment size */
552
553         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
554 }
555
556 /*
557  * deliver reply data to an FS.RemoveFile or FS.RemoveDir
558  */
559 static int afs_deliver_fs_remove(struct afs_call *call,
560                                  struct sk_buff *skb, bool last)
561 {
562         struct afs_vnode *vnode = call->reply;
563         const __be32 *bp;
564
565         _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
566
567         afs_transfer_reply(call, skb);
568         if (!last)
569                 return 0;
570
571         if (call->reply_size != call->reply_max)
572                 return -EBADMSG;
573
574         /* unmarshall the reply once we've received all of it */
575         bp = call->buffer;
576         xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
577         /* xdr_decode_AFSVolSync(&bp, call->replyX); */
578
579         _leave(" = 0 [done]");
580         return 0;
581 }
582
583 /*
584  * FS.RemoveDir/FS.RemoveFile operation type
585  */
586 static const struct afs_call_type afs_RXFSRemoveXXXX = {
587         .name           = "FS.RemoveXXXX",
588         .deliver        = afs_deliver_fs_remove,
589         .abort_to_error = afs_abort_to_error,
590         .destructor     = afs_flat_call_destructor,
591 };
592
593 /*
594  * remove a file or directory
595  */
596 int afs_fs_remove(struct afs_server *server,
597                   struct key *key,
598                   struct afs_vnode *vnode,
599                   const char *name,
600                   bool isdir,
601                   const struct afs_wait_mode *wait_mode)
602 {
603         struct afs_call *call;
604         size_t namesz, reqsz, padsz;
605         __be32 *bp;
606
607         _enter("");
608
609         namesz = strlen(name);
610         padsz = (4 - (namesz & 3)) & 3;
611         reqsz = (5 * 4) + namesz + padsz;
612
613         call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
614         if (!call)
615                 return -ENOMEM;
616
617         call->key = key;
618         call->reply = vnode;
619         call->service_id = FS_SERVICE;
620         call->port = htons(AFS_FS_PORT);
621
622         /* marshall the parameters */
623         bp = call->request;
624         *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
625         *bp++ = htonl(vnode->fid.vid);
626         *bp++ = htonl(vnode->fid.vnode);
627         *bp++ = htonl(vnode->fid.unique);
628         *bp++ = htonl(namesz);
629         memcpy(bp, name, namesz);
630         bp = (void *) bp + namesz;
631         if (padsz > 0) {
632                 memset(bp, 0, padsz);
633                 bp = (void *) bp + padsz;
634         }
635
636         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
637 }
638
639 /*
640  * deliver reply data to an FS.Link
641  */
642 static int afs_deliver_fs_link(struct afs_call *call,
643                                struct sk_buff *skb, bool last)
644 {
645         struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
646         const __be32 *bp;
647
648         _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
649
650         afs_transfer_reply(call, skb);
651         if (!last)
652                 return 0;
653
654         if (call->reply_size != call->reply_max)
655                 return -EBADMSG;
656
657         /* unmarshall the reply once we've received all of it */
658         bp = call->buffer;
659         xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
660         xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode);
661         /* xdr_decode_AFSVolSync(&bp, call->replyX); */
662
663         _leave(" = 0 [done]");
664         return 0;
665 }
666
667 /*
668  * FS.Link operation type
669  */
670 static const struct afs_call_type afs_RXFSLink = {
671         .name           = "FS.Link",
672         .deliver        = afs_deliver_fs_link,
673         .abort_to_error = afs_abort_to_error,
674         .destructor     = afs_flat_call_destructor,
675 };
676
677 /*
678  * make a hard link
679  */
680 int afs_fs_link(struct afs_server *server,
681                 struct key *key,
682                 struct afs_vnode *dvnode,
683                 struct afs_vnode *vnode,
684                 const char *name,
685                 const struct afs_wait_mode *wait_mode)
686 {
687         struct afs_call *call;
688         size_t namesz, reqsz, padsz;
689         __be32 *bp;
690
691         _enter("");
692
693         namesz = strlen(name);
694         padsz = (4 - (namesz & 3)) & 3;
695         reqsz = (5 * 4) + namesz + padsz + (3 * 4);
696
697         call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
698         if (!call)
699                 return -ENOMEM;
700
701         call->key = key;
702         call->reply = dvnode;
703         call->reply2 = vnode;
704         call->service_id = FS_SERVICE;
705         call->port = htons(AFS_FS_PORT);
706
707         /* marshall the parameters */
708         bp = call->request;
709         *bp++ = htonl(FSLINK);
710         *bp++ = htonl(dvnode->fid.vid);
711         *bp++ = htonl(dvnode->fid.vnode);
712         *bp++ = htonl(dvnode->fid.unique);
713         *bp++ = htonl(namesz);
714         memcpy(bp, name, namesz);
715         bp = (void *) bp + namesz;
716         if (padsz > 0) {
717                 memset(bp, 0, padsz);
718                 bp = (void *) bp + padsz;
719         }
720         *bp++ = htonl(vnode->fid.vid);
721         *bp++ = htonl(vnode->fid.vnode);
722         *bp++ = htonl(vnode->fid.unique);
723
724         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
725 }
726
727 /*
728  * deliver reply data to an FS.Symlink
729  */
730 static int afs_deliver_fs_symlink(struct afs_call *call,
731                                   struct sk_buff *skb, bool last)
732 {
733         struct afs_vnode *vnode = call->reply;
734         const __be32 *bp;
735
736         _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
737
738         afs_transfer_reply(call, skb);
739         if (!last)
740                 return 0;
741
742         if (call->reply_size != call->reply_max)
743                 return -EBADMSG;
744
745         /* unmarshall the reply once we've received all of it */
746         bp = call->buffer;
747         xdr_decode_AFSFid(&bp, call->reply2);
748         xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
749         xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
750         /* xdr_decode_AFSVolSync(&bp, call->replyX); */
751
752         _leave(" = 0 [done]");
753         return 0;
754 }
755
756 /*
757  * FS.Symlink operation type
758  */
759 static const struct afs_call_type afs_RXFSSymlink = {
760         .name           = "FS.Symlink",
761         .deliver        = afs_deliver_fs_symlink,
762         .abort_to_error = afs_abort_to_error,
763         .destructor     = afs_flat_call_destructor,
764 };
765
766 /*
767  * create a symbolic link
768  */
769 int afs_fs_symlink(struct afs_server *server,
770                    struct key *key,
771                    struct afs_vnode *vnode,
772                    const char *name,
773                    const char *contents,
774                    struct afs_fid *newfid,
775                    struct afs_file_status *newstatus,
776                    const struct afs_wait_mode *wait_mode)
777 {
778         struct afs_call *call;
779         size_t namesz, reqsz, padsz, c_namesz, c_padsz;
780         __be32 *bp;
781
782         _enter("");
783
784         namesz = strlen(name);
785         padsz = (4 - (namesz & 3)) & 3;
786
787         c_namesz = strlen(contents);
788         c_padsz = (4 - (c_namesz & 3)) & 3;
789
790         reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
791
792         call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
793                                    (3 + 21 + 21 + 6) * 4);
794         if (!call)
795                 return -ENOMEM;
796
797         call->key = key;
798         call->reply = vnode;
799         call->reply2 = newfid;
800         call->reply3 = newstatus;
801         call->service_id = FS_SERVICE;
802         call->port = htons(AFS_FS_PORT);
803
804         /* marshall the parameters */
805         bp = call->request;
806         *bp++ = htonl(FSSYMLINK);
807         *bp++ = htonl(vnode->fid.vid);
808         *bp++ = htonl(vnode->fid.vnode);
809         *bp++ = htonl(vnode->fid.unique);
810         *bp++ = htonl(namesz);
811         memcpy(bp, name, namesz);
812         bp = (void *) bp + namesz;
813         if (padsz > 0) {
814                 memset(bp, 0, padsz);
815                 bp = (void *) bp + padsz;
816         }
817         *bp++ = htonl(c_namesz);
818         memcpy(bp, contents, c_namesz);
819         bp = (void *) bp + c_namesz;
820         if (c_padsz > 0) {
821                 memset(bp, 0, c_padsz);
822                 bp = (void *) bp + c_padsz;
823         }
824         *bp++ = htonl(AFS_SET_MODE);
825         *bp++ = 0; /* mtime */
826         *bp++ = 0; /* owner */
827         *bp++ = 0; /* group */
828         *bp++ = htonl(S_IRWXUGO); /* unix mode */
829         *bp++ = 0; /* segment size */
830
831         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
832 }
833
834 /*
835  * deliver reply data to an FS.Rename
836  */
837 static int afs_deliver_fs_rename(struct afs_call *call,
838                                   struct sk_buff *skb, bool last)
839 {
840         struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
841         const __be32 *bp;
842
843         _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
844
845         afs_transfer_reply(call, skb);
846         if (!last)
847                 return 0;
848
849         if (call->reply_size != call->reply_max)
850                 return -EBADMSG;
851
852         /* unmarshall the reply once we've received all of it */
853         bp = call->buffer;
854         xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode);
855         if (new_dvnode != orig_dvnode)
856                 xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode);
857         /* xdr_decode_AFSVolSync(&bp, call->replyX); */
858
859         _leave(" = 0 [done]");
860         return 0;
861 }
862
863 /*
864  * FS.Rename operation type
865  */
866 static const struct afs_call_type afs_RXFSRename = {
867         .name           = "FS.Rename",
868         .deliver        = afs_deliver_fs_rename,
869         .abort_to_error = afs_abort_to_error,
870         .destructor     = afs_flat_call_destructor,
871 };
872
873 /*
874  * create a symbolic link
875  */
876 int afs_fs_rename(struct afs_server *server,
877                   struct key *key,
878                   struct afs_vnode *orig_dvnode,
879                   const char *orig_name,
880                   struct afs_vnode *new_dvnode,
881                   const char *new_name,
882                   const struct afs_wait_mode *wait_mode)
883 {
884         struct afs_call *call;
885         size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
886         __be32 *bp;
887
888         _enter("");
889
890         o_namesz = strlen(orig_name);
891         o_padsz = (4 - (o_namesz & 3)) & 3;
892
893         n_namesz = strlen(new_name);
894         n_padsz = (4 - (n_namesz & 3)) & 3;
895
896         reqsz = (4 * 4) +
897                 4 + o_namesz + o_padsz +
898                 (3 * 4) +
899                 4 + n_namesz + n_padsz;
900
901         call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
902         if (!call)
903                 return -ENOMEM;
904
905         call->key = key;
906         call->reply = orig_dvnode;
907         call->reply2 = new_dvnode;
908         call->service_id = FS_SERVICE;
909         call->port = htons(AFS_FS_PORT);
910
911         /* marshall the parameters */
912         bp = call->request;
913         *bp++ = htonl(FSRENAME);
914         *bp++ = htonl(orig_dvnode->fid.vid);
915         *bp++ = htonl(orig_dvnode->fid.vnode);
916         *bp++ = htonl(orig_dvnode->fid.unique);
917         *bp++ = htonl(o_namesz);
918         memcpy(bp, orig_name, o_namesz);
919         bp = (void *) bp + o_namesz;
920         if (o_padsz > 0) {
921                 memset(bp, 0, o_padsz);
922                 bp = (void *) bp + o_padsz;
923         }
924
925         *bp++ = htonl(new_dvnode->fid.vid);
926         *bp++ = htonl(new_dvnode->fid.vnode);
927         *bp++ = htonl(new_dvnode->fid.unique);
928         *bp++ = htonl(n_namesz);
929         memcpy(bp, new_name, n_namesz);
930         bp = (void *) bp + n_namesz;
931         if (n_padsz > 0) {
932                 memset(bp, 0, n_padsz);
933                 bp = (void *) bp + n_padsz;
934         }
935
936         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
937 }