1 /* fsclient.c: AFS File Server client stubs
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/init.h>
13 #include <linux/sched.h>
14 #include <rxrpc/rxrpc.h>
15 #include <rxrpc/transport.h>
16 #include <rxrpc/connection.h>
17 #include <rxrpc/call.h>
19 #include "cmservice.h"
25 #define FSFETCHSTATUS 132 /* AFS Fetch file status */
26 #define FSFETCHDATA 130 /* AFS Fetch file data */
27 #define FSGIVEUPCALLBACKS 147 /* AFS Discard callback promises */
28 #define FSGETVOLUMEINFO 148 /* AFS Get root volume information */
29 #define FSGETROOTVOLUME 151 /* AFS Get root volume name */
30 #define FSLOOKUP 161 /* AFS lookup file in directory */
32 /*****************************************************************************/
34 * map afs abort codes to/from Linux error codes
35 * - called with call->lock held
37 static void afs_rxfs_aemap(struct rxrpc_call *call)
39 switch (call->app_err_state) {
40 case RXRPC_ESTATE_LOCAL_ABORT:
41 call->app_abort_code = -call->app_errno;
43 case RXRPC_ESTATE_PEER_ABORT:
44 call->app_errno = afs_abort_to_error(call->app_abort_code);
49 } /* end afs_rxfs_aemap() */
51 /*****************************************************************************/
53 * get the root volume name from a fileserver
54 * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2
57 int afs_rxfs_get_root_volume(struct afs_server *server,
58 char *buf, size_t *buflen)
60 struct rxrpc_connection *conn;
61 struct rxrpc_call *call;
67 DECLARE_WAITQUEUE(myself, current);
69 kenter("%p,%p,%u",server, buf, *buflen);
71 /* get hold of the fileserver connection */
72 ret = afs_server_get_fsconn(server, &conn);
76 /* create a call through that connection */
77 ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call);
79 printk("kAFS: Unable to create call: %d\n", ret);
82 call->app_opcode = FSGETROOTVOLUME;
84 /* we want to get event notifications from the call */
85 add_wait_queue(&call->waitq, &myself);
87 /* marshall the parameters */
88 param[0] = htonl(FSGETROOTVOLUME);
90 piov[0].iov_len = sizeof(param);
91 piov[0].iov_base = param;
93 /* send the parameters to the server */
94 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
99 /* wait for the reply to completely arrive */
101 set_current_state(TASK_INTERRUPTIBLE);
102 if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY ||
103 signal_pending(current))
107 set_current_state(TASK_RUNNING);
110 if (signal_pending(current))
113 switch (call->app_call_state) {
114 case RXRPC_CSTATE_ERROR:
115 ret = call->app_errno;
116 kdebug("Got Error: %d", ret);
119 case RXRPC_CSTATE_CLNT_GOT_REPLY:
121 kdebug("Got Reply: qty=%d", call->app_ready_qty);
124 if (call->app_ready_qty <= 4)
127 ret = rxrpc_call_read_data(call, NULL, call->app_ready_qty, 0);
132 /* unmarshall the reply */
134 for (loop = 0; loop < 65; loop++)
135 entry->name[loop] = ntohl(*bp++);
138 entry->type = ntohl(*bp++);
139 entry->num_servers = ntohl(*bp++);
141 for (loop = 0; loop < 8; loop++)
142 entry->servers[loop].addr.s_addr = *bp++;
144 for (loop = 0; loop < 8; loop++)
145 entry->servers[loop].partition = ntohl(*bp++);
147 for (loop = 0; loop < 8; loop++)
148 entry->servers[loop].flags = ntohl(*bp++);
150 for (loop = 0; loop < 3; loop++)
151 entry->volume_ids[loop] = ntohl(*bp++);
153 entry->clone_id = ntohl(*bp++);
154 entry->flags = ntohl(*bp);
166 set_current_state(TASK_UNINTERRUPTIBLE);
167 rxrpc_call_abort(call, ret);
170 set_current_state(TASK_RUNNING);
171 remove_wait_queue(&call->waitq, &myself);
172 rxrpc_put_call(call);
174 afs_server_release_fsconn(server, conn);
178 } /* end afs_rxfs_get_root_volume() */
181 /*****************************************************************************/
183 * get information about a volume
186 int afs_rxfs_get_volume_info(struct afs_server *server,
188 struct afs_volume_info *vinfo)
190 struct rxrpc_connection *conn;
191 struct rxrpc_call *call;
195 u32 param[2], *bp, zero;
197 DECLARE_WAITQUEUE(myself, current);
199 _enter("%p,%s,%p", server, name, vinfo);
201 /* get hold of the fileserver connection */
202 ret = afs_server_get_fsconn(server, &conn);
206 /* create a call through that connection */
207 ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call);
209 printk("kAFS: Unable to create call: %d\n", ret);
212 call->app_opcode = FSGETVOLUMEINFO;
214 /* we want to get event notifications from the call */
215 add_wait_queue(&call->waitq, &myself);
217 /* marshall the parameters */
218 piov[1].iov_len = strlen(name);
219 piov[1].iov_base = (char *) name;
222 piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
223 piov[2].iov_base = &zero;
225 param[0] = htonl(FSGETVOLUMEINFO);
226 param[1] = htonl(piov[1].iov_len);
228 piov[0].iov_len = sizeof(param);
229 piov[0].iov_base = param;
231 /* send the parameters to the server */
232 ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS,
237 /* wait for the reply to completely arrive */
238 bp = rxrpc_call_alloc_scratch(call, 64);
240 ret = rxrpc_call_read_data(call, bp, 64,
241 RXRPC_CALL_READ_BLOCK |
242 RXRPC_CALL_READ_ALL);
244 if (ret == -ECONNABORTED) {
245 ret = call->app_errno;
251 /* unmarshall the reply */
252 vinfo->vid = ntohl(*bp++);
253 vinfo->type = ntohl(*bp++);
255 vinfo->type_vids[0] = ntohl(*bp++);
256 vinfo->type_vids[1] = ntohl(*bp++);
257 vinfo->type_vids[2] = ntohl(*bp++);
258 vinfo->type_vids[3] = ntohl(*bp++);
259 vinfo->type_vids[4] = ntohl(*bp++);
261 vinfo->nservers = ntohl(*bp++);
262 vinfo->servers[0].addr.s_addr = *bp++;
263 vinfo->servers[1].addr.s_addr = *bp++;
264 vinfo->servers[2].addr.s_addr = *bp++;
265 vinfo->servers[3].addr.s_addr = *bp++;
266 vinfo->servers[4].addr.s_addr = *bp++;
267 vinfo->servers[5].addr.s_addr = *bp++;
268 vinfo->servers[6].addr.s_addr = *bp++;
269 vinfo->servers[7].addr.s_addr = *bp++;
272 if (vinfo->nservers > 8)
279 set_current_state(TASK_RUNNING);
280 remove_wait_queue(&call->waitq, &myself);
281 rxrpc_put_call(call);
283 afs_server_release_fsconn(server, conn);
289 set_current_state(TASK_UNINTERRUPTIBLE);
290 rxrpc_call_abort(call, ret);
294 } /* end afs_rxfs_get_volume_info() */
297 /*****************************************************************************/
299 * fetch the status information for a file
301 int afs_rxfs_fetch_file_status(struct afs_server *server,
302 struct afs_vnode *vnode,
303 struct afs_volsync *volsync)
305 struct afs_server_callslot callslot;
306 struct rxrpc_call *call;
312 DECLARE_WAITQUEUE(myself, current);
314 _enter("%p,{%u,%u,%u}",
315 server, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
317 /* get hold of the fileserver connection */
318 ret = afs_server_request_callslot(server, &callslot);
322 /* create a call through that connection */
323 ret = rxrpc_create_call(callslot.conn, NULL, NULL, afs_rxfs_aemap,
326 printk("kAFS: Unable to create call: %d\n", ret);
329 call->app_opcode = FSFETCHSTATUS;
331 /* we want to get event notifications from the call */
332 add_wait_queue(&call->waitq, &myself);
334 /* marshall the parameters */
335 bp = rxrpc_call_alloc_scratch(call, 16);
336 bp[0] = htonl(FSFETCHSTATUS);
337 bp[1] = htonl(vnode->fid.vid);
338 bp[2] = htonl(vnode->fid.vnode);
339 bp[3] = htonl(vnode->fid.unique);
341 piov[0].iov_len = 16;
342 piov[0].iov_base = bp;
344 /* send the parameters to the server */
345 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
350 /* wait for the reply to completely arrive */
351 bp = rxrpc_call_alloc_scratch(call, 120);
353 ret = rxrpc_call_read_data(call, bp, 120,
354 RXRPC_CALL_READ_BLOCK |
355 RXRPC_CALL_READ_ALL);
357 if (ret == -ECONNABORTED) {
358 ret = call->app_errno;
364 /* unmarshall the reply */
365 vnode->status.if_version = ntohl(*bp++);
366 vnode->status.type = ntohl(*bp++);
367 vnode->status.nlink = ntohl(*bp++);
368 vnode->status.size = ntohl(*bp++);
369 vnode->status.version = ntohl(*bp++);
370 vnode->status.author = ntohl(*bp++);
371 vnode->status.owner = ntohl(*bp++);
372 vnode->status.caller_access = ntohl(*bp++);
373 vnode->status.anon_access = ntohl(*bp++);
374 vnode->status.mode = ntohl(*bp++);
375 vnode->status.parent.vid = vnode->fid.vid;
376 vnode->status.parent.vnode = ntohl(*bp++);
377 vnode->status.parent.unique = ntohl(*bp++);
379 vnode->status.mtime_client = ntohl(*bp++);
380 vnode->status.mtime_server = ntohl(*bp++);
382 bp++; /* sync counter */
383 vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
388 vnode->cb_version = ntohl(*bp++);
389 vnode->cb_expiry = ntohl(*bp++);
390 vnode->cb_type = ntohl(*bp++);
393 volsync->creation = ntohl(*bp++);
401 _debug("Data Version %llx\n", vnode->status.version);
407 set_current_state(TASK_RUNNING);
408 remove_wait_queue(&call->waitq, &myself);
409 rxrpc_put_call(call);
411 afs_server_release_callslot(server, &callslot);
413 _leave(" = %d", ret);
417 set_current_state(TASK_UNINTERRUPTIBLE);
418 rxrpc_call_abort(call, ret);
421 } /* end afs_rxfs_fetch_file_status() */
423 /*****************************************************************************/
425 * fetch the contents of a file or directory
427 int afs_rxfs_fetch_file_data(struct afs_server *server,
428 struct afs_vnode *vnode,
429 struct afs_rxfs_fetch_descriptor *desc,
430 struct afs_volsync *volsync)
432 struct afs_server_callslot callslot;
433 struct rxrpc_call *call;
439 DECLARE_WAITQUEUE(myself, current);
441 _enter("%p,{fid={%u,%u,%u},sz=%Zu,of=%lu}",
449 /* get hold of the fileserver connection */
450 ret = afs_server_request_callslot(server, &callslot);
454 /* create a call through that connection */
455 ret = rxrpc_create_call(callslot.conn, NULL, NULL, afs_rxfs_aemap, &call);
457 printk("kAFS: Unable to create call: %d\n", ret);
460 call->app_opcode = FSFETCHDATA;
462 /* we want to get event notifications from the call */
463 add_wait_queue(&call->waitq, &myself);
465 /* marshall the parameters */
466 bp = rxrpc_call_alloc_scratch(call, 24);
467 bp[0] = htonl(FSFETCHDATA);
468 bp[1] = htonl(desc->fid.vid);
469 bp[2] = htonl(desc->fid.vnode);
470 bp[3] = htonl(desc->fid.unique);
471 bp[4] = htonl(desc->offset);
472 bp[5] = htonl(desc->size);
474 piov[0].iov_len = 24;
475 piov[0].iov_base = bp;
477 /* send the parameters to the server */
478 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
483 /* wait for the data count to arrive */
484 ret = rxrpc_call_read_data(call, bp, 4, RXRPC_CALL_READ_BLOCK);
488 desc->actual = ntohl(bp[0]);
489 if (desc->actual != desc->size) {
494 /* call the app to read the actual data */
495 rxrpc_call_reset_scratch(call);
497 ret = rxrpc_call_read_data(call, desc->buffer, desc->actual,
498 RXRPC_CALL_READ_BLOCK);
502 /* wait for the rest of the reply to completely arrive */
503 rxrpc_call_reset_scratch(call);
504 bp = rxrpc_call_alloc_scratch(call, 120);
506 ret = rxrpc_call_read_data(call, bp, 120,
507 RXRPC_CALL_READ_BLOCK |
508 RXRPC_CALL_READ_ALL);
512 /* unmarshall the reply */
513 vnode->status.if_version = ntohl(*bp++);
514 vnode->status.type = ntohl(*bp++);
515 vnode->status.nlink = ntohl(*bp++);
516 vnode->status.size = ntohl(*bp++);
517 vnode->status.version = ntohl(*bp++);
518 vnode->status.author = ntohl(*bp++);
519 vnode->status.owner = ntohl(*bp++);
520 vnode->status.caller_access = ntohl(*bp++);
521 vnode->status.anon_access = ntohl(*bp++);
522 vnode->status.mode = ntohl(*bp++);
523 vnode->status.parent.vid = desc->fid.vid;
524 vnode->status.parent.vnode = ntohl(*bp++);
525 vnode->status.parent.unique = ntohl(*bp++);
527 vnode->status.mtime_client = ntohl(*bp++);
528 vnode->status.mtime_server = ntohl(*bp++);
530 bp++; /* sync counter */
531 vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
536 vnode->cb_version = ntohl(*bp++);
537 vnode->cb_expiry = ntohl(*bp++);
538 vnode->cb_type = ntohl(*bp++);
541 volsync->creation = ntohl(*bp++);
553 set_current_state(TASK_RUNNING);
554 remove_wait_queue(&call->waitq,&myself);
555 rxrpc_put_call(call);
557 afs_server_release_callslot(server, &callslot);
559 _leave(" = %d", ret);
563 if (ret == -ECONNABORTED) {
564 ret = call->app_errno;
569 set_current_state(TASK_UNINTERRUPTIBLE);
570 rxrpc_call_abort(call, ret);
574 } /* end afs_rxfs_fetch_file_data() */
576 /*****************************************************************************/
578 * ask the AFS fileserver to discard a callback request on a file
580 int afs_rxfs_give_up_callback(struct afs_server *server,
581 struct afs_vnode *vnode)
583 struct afs_server_callslot callslot;
584 struct rxrpc_call *call;
590 DECLARE_WAITQUEUE(myself, current);
592 _enter("%p,{%u,%u,%u}",
593 server, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
595 /* get hold of the fileserver connection */
596 ret = afs_server_request_callslot(server, &callslot);
600 /* create a call through that connection */
601 ret = rxrpc_create_call(callslot.conn, NULL, NULL, afs_rxfs_aemap, &call);
603 printk("kAFS: Unable to create call: %d\n", ret);
606 call->app_opcode = FSGIVEUPCALLBACKS;
608 /* we want to get event notifications from the call */
609 add_wait_queue(&call->waitq, &myself);
611 /* marshall the parameters */
612 bp = rxrpc_call_alloc_scratch(call, (1 + 4 + 4) * 4);
614 piov[0].iov_len = (1 + 4 + 4) * 4;
615 piov[0].iov_base = bp;
617 *bp++ = htonl(FSGIVEUPCALLBACKS);
619 *bp++ = htonl(vnode->fid.vid);
620 *bp++ = htonl(vnode->fid.vnode);
621 *bp++ = htonl(vnode->fid.unique);
623 *bp++ = htonl(vnode->cb_version);
624 *bp++ = htonl(vnode->cb_expiry);
625 *bp++ = htonl(vnode->cb_type);
627 /* send the parameters to the server */
628 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
633 /* wait for the reply to completely arrive */
635 set_current_state(TASK_INTERRUPTIBLE);
636 if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY ||
637 signal_pending(current))
641 set_current_state(TASK_RUNNING);
644 if (signal_pending(current))
647 switch (call->app_call_state) {
648 case RXRPC_CSTATE_ERROR:
649 ret = call->app_errno;
652 case RXRPC_CSTATE_CLNT_GOT_REPLY:
661 set_current_state(TASK_RUNNING);
662 remove_wait_queue(&call->waitq, &myself);
663 rxrpc_put_call(call);
665 afs_server_release_callslot(server, &callslot);
671 set_current_state(TASK_UNINTERRUPTIBLE);
672 rxrpc_call_abort(call, ret);
675 } /* end afs_rxfs_give_up_callback() */
677 /*****************************************************************************/
679 * look a filename up in a directory
680 * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2
683 int afs_rxfs_lookup(struct afs_server *server,
684 struct afs_vnode *dir,
685 const char *filename,
686 struct afs_vnode *vnode,
687 struct afs_volsync *volsync)
689 struct rxrpc_connection *conn;
690 struct rxrpc_call *call;
696 DECLARE_WAITQUEUE(myself, current);
698 kenter("%p,{%u,%u,%u},%s",
699 server, fid->vid, fid->vnode, fid->unique, filename);
701 /* get hold of the fileserver connection */
702 ret = afs_server_get_fsconn(server, &conn);
706 /* create a call through that connection */
707 ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call);
709 printk("kAFS: Unable to create call: %d\n", ret);
712 call->app_opcode = FSLOOKUP;
714 /* we want to get event notifications from the call */
715 add_wait_queue(&call->waitq,&myself);
717 /* marshall the parameters */
718 bp = rxrpc_call_alloc_scratch(call, 20);
722 piov[0].iov_len = 20;
723 piov[0].iov_base = bp;
724 piov[1].iov_len = strlen(filename);
725 piov[1].iov_base = (char *) filename;
726 piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
727 piov[2].iov_base = &zero;
729 *bp++ = htonl(FSLOOKUP);
730 *bp++ = htonl(dirfid->vid);
731 *bp++ = htonl(dirfid->vnode);
732 *bp++ = htonl(dirfid->unique);
733 *bp++ = htonl(piov[1].iov_len);
735 /* send the parameters to the server */
736 ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS,
741 /* wait for the reply to completely arrive */
742 bp = rxrpc_call_alloc_scratch(call, 220);
744 ret = rxrpc_call_read_data(call, bp, 220,
745 RXRPC_CALL_READ_BLOCK |
746 RXRPC_CALL_READ_ALL);
748 if (ret == -ECONNABORTED) {
749 ret = call->app_errno;
755 /* unmarshall the reply */
756 fid->vid = ntohl(*bp++);
757 fid->vnode = ntohl(*bp++);
758 fid->unique = ntohl(*bp++);
760 vnode->status.if_version = ntohl(*bp++);
761 vnode->status.type = ntohl(*bp++);
762 vnode->status.nlink = ntohl(*bp++);
763 vnode->status.size = ntohl(*bp++);
764 vnode->status.version = ntohl(*bp++);
765 vnode->status.author = ntohl(*bp++);
766 vnode->status.owner = ntohl(*bp++);
767 vnode->status.caller_access = ntohl(*bp++);
768 vnode->status.anon_access = ntohl(*bp++);
769 vnode->status.mode = ntohl(*bp++);
770 vnode->status.parent.vid = dirfid->vid;
771 vnode->status.parent.vnode = ntohl(*bp++);
772 vnode->status.parent.unique = ntohl(*bp++);
774 vnode->status.mtime_client = ntohl(*bp++);
775 vnode->status.mtime_server = ntohl(*bp++);
777 bp++; /* sync counter */
778 vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
783 dir->status.if_version = ntohl(*bp++);
784 dir->status.type = ntohl(*bp++);
785 dir->status.nlink = ntohl(*bp++);
786 dir->status.size = ntohl(*bp++);
787 dir->status.version = ntohl(*bp++);
788 dir->status.author = ntohl(*bp++);
789 dir->status.owner = ntohl(*bp++);
790 dir->status.caller_access = ntohl(*bp++);
791 dir->status.anon_access = ntohl(*bp++);
792 dir->status.mode = ntohl(*bp++);
793 dir->status.parent.vid = dirfid->vid;
794 dir->status.parent.vnode = ntohl(*bp++);
795 dir->status.parent.unique = ntohl(*bp++);
797 dir->status.mtime_client = ntohl(*bp++);
798 dir->status.mtime_server = ntohl(*bp++);
800 bp++; /* sync counter */
801 dir->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
806 callback->fid = *fid;
807 callback->version = ntohl(*bp++);
808 callback->expiry = ntohl(*bp++);
809 callback->type = ntohl(*bp++);
812 volsync->creation = ntohl(*bp++);
824 set_current_state(TASK_RUNNING);
825 remove_wait_queue(&call->waitq, &myself);
826 rxrpc_put_call(call);
828 afs_server_release_fsconn(server, conn);
834 set_current_state(TASK_UNINTERRUPTIBLE);
835 rxrpc_call_abort(call, ret);
838 } /* end afs_rxfs_lookup() */