123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- /* AFS File Server client stubs
- *
- * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
- #include <linux/init.h>
- #include <linux/sched.h>
- #include <linux/circ_buf.h>
- #include "internal.h"
- #include "afs_fs.h"
- /*
- * decode an AFSFetchStatus block
- */
- static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
- struct afs_vnode *vnode)
- {
- const __be32 *bp = *_bp;
- umode_t mode;
- u64 data_version;
- u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
- #define EXTRACT(DST) \
- do { \
- u32 x = ntohl(*bp++); \
- changed |= DST - x; \
- DST = x; \
- } while (0)
- vnode->status.if_version = ntohl(*bp++);
- EXTRACT(vnode->status.type);
- vnode->status.nlink = ntohl(*bp++);
- EXTRACT(vnode->status.size);
- data_version = ntohl(*bp++);
- EXTRACT(vnode->status.author);
- EXTRACT(vnode->status.owner);
- EXTRACT(vnode->status.caller_access); /* call ticket dependent */
- EXTRACT(vnode->status.anon_access);
- EXTRACT(vnode->status.mode);
- vnode->status.parent.vid = vnode->fid.vid;
- EXTRACT(vnode->status.parent.vnode);
- EXTRACT(vnode->status.parent.unique);
- bp++; /* seg size */
- vnode->status.mtime_client = ntohl(*bp++);
- vnode->status.mtime_server = ntohl(*bp++);
- bp++; /* group */
- bp++; /* sync counter */
- data_version |= (u64) ntohl(*bp++) << 32;
- bp++; /* spare2 */
- bp++; /* spare3 */
- bp++; /* spare4 */
- *_bp = bp;
- if (changed) {
- _debug("vnode changed");
- set_bit(AFS_VNODE_CHANGED, &vnode->flags);
- vnode->vfs_inode.i_uid = vnode->status.owner;
- vnode->vfs_inode.i_size = vnode->status.size;
- vnode->vfs_inode.i_version = vnode->fid.unique;
- vnode->status.mode &= S_IALLUGO;
- mode = vnode->vfs_inode.i_mode;
- mode &= ~S_IALLUGO;
- mode |= vnode->status.mode;
- vnode->vfs_inode.i_mode = mode;
- }
- _debug("vnode time %lx, %lx",
- vnode->status.mtime_client, vnode->status.mtime_server);
- vnode->vfs_inode.i_ctime.tv_sec = vnode->status.mtime_server;
- vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime;
- vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime;
- if (vnode->status.data_version != data_version) {
- _debug("vnode modified %llx", data_version);
- vnode->status.data_version = data_version;
- set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
- set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
- }
- }
- /*
- * decode an AFSCallBack block
- */
- static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
- {
- const __be32 *bp = *_bp;
- vnode->cb_version = ntohl(*bp++);
- vnode->cb_expiry = ntohl(*bp++);
- vnode->cb_type = ntohl(*bp++);
- vnode->cb_expires = vnode->cb_expiry + get_seconds();
- *_bp = bp;
- }
- /*
- * decode an AFSVolSync block
- */
- static void xdr_decode_AFSVolSync(const __be32 **_bp,
- struct afs_volsync *volsync)
- {
- const __be32 *bp = *_bp;
- volsync->creation = ntohl(*bp++);
- bp++; /* spare2 */
- bp++; /* spare3 */
- bp++; /* spare4 */
- bp++; /* spare5 */
- bp++; /* spare6 */
- *_bp = bp;
- }
- /*
- * deliver reply data to an FS.FetchStatus
- */
- static int afs_deliver_fs_fetch_status(struct afs_call *call,
- struct sk_buff *skb, bool last)
- {
- const __be32 *bp;
- _enter(",,%u", last);
- afs_transfer_reply(call, skb);
- if (!last)
- return 0;
- if (call->reply_size != call->reply_max)
- return -EBADMSG;
- /* unmarshall the reply once we've received all of it */
- bp = call->buffer;
- xdr_decode_AFSFetchStatus(&bp, call->reply);
- xdr_decode_AFSCallBack(&bp, call->reply);
- if (call->reply2)
- xdr_decode_AFSVolSync(&bp, call->reply2);
- _leave(" = 0 [done]");
- return 0;
- }
- /*
- * FS.FetchStatus operation type
- */
- static const struct afs_call_type afs_RXFSFetchStatus = {
- .deliver = afs_deliver_fs_fetch_status,
- .abort_to_error = afs_abort_to_error,
- .destructor = afs_flat_call_destructor,
- };
- /*
- * fetch the status information for a file
- */
- int afs_fs_fetch_file_status(struct afs_server *server,
- struct afs_vnode *vnode,
- struct afs_volsync *volsync,
- const struct afs_wait_mode *wait_mode)
- {
- struct afs_call *call;
- __be32 *bp;
- _enter("");
- call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120);
- if (!call)
- return -ENOMEM;
- call->reply = vnode;
- call->reply2 = volsync;
- call->service_id = FS_SERVICE;
- call->port = htons(AFS_FS_PORT);
- /* marshall the parameters */
- bp = call->request;
- bp[0] = htonl(FSFETCHSTATUS);
- bp[1] = htonl(vnode->fid.vid);
- bp[2] = htonl(vnode->fid.vnode);
- bp[3] = htonl(vnode->fid.unique);
- return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
- }
- /*
- * deliver reply data to an FS.FetchData
- */
- static int afs_deliver_fs_fetch_data(struct afs_call *call,
- struct sk_buff *skb, bool last)
- {
- const __be32 *bp;
- struct page *page;
- void *buffer;
- int ret;
- _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
- switch (call->unmarshall) {
- case 0:
- call->offset = 0;
- call->unmarshall++;
- /* extract the returned data length */
- case 1:
- _debug("extract data length");
- ret = afs_extract_data(call, skb, last, &call->tmp, 4);
- switch (ret) {
- case 0: break;
- case -EAGAIN: return 0;
- default: return ret;
- }
- call->count = ntohl(call->tmp);
- _debug("DATA length: %u", call->count);
- if (call->count > PAGE_SIZE)
- return -EBADMSG;
- call->offset = 0;
- call->unmarshall++;
- if (call->count < PAGE_SIZE) {
- buffer = kmap_atomic(call->reply3, KM_USER0);
- memset(buffer + PAGE_SIZE - call->count, 0,
- call->count);
- kunmap_atomic(buffer, KM_USER0);
- }
- /* extract the returned data */
- case 2:
- _debug("extract data");
- page = call->reply3;
- buffer = kmap_atomic(page, KM_USER0);
- ret = afs_extract_data(call, skb, last, buffer, call->count);
- kunmap_atomic(buffer, KM_USER0);
- switch (ret) {
- case 0: break;
- case -EAGAIN: return 0;
- default: return ret;
- }
- call->offset = 0;
- call->unmarshall++;
- /* extract the metadata */
- case 3:
- ret = afs_extract_data(call, skb, last, call->buffer, 120);
- switch (ret) {
- case 0: break;
- case -EAGAIN: return 0;
- default: return ret;
- }
- bp = call->buffer;
- xdr_decode_AFSFetchStatus(&bp, call->reply);
- xdr_decode_AFSCallBack(&bp, call->reply);
- if (call->reply2)
- xdr_decode_AFSVolSync(&bp, call->reply2);
- call->offset = 0;
- call->unmarshall++;
- case 4:
- _debug("trailer");
- if (skb->len != 0)
- return -EBADMSG;
- break;
- }
- if (!last)
- return 0;
- _leave(" = 0 [done]");
- return 0;
- }
- /*
- * FS.FetchData operation type
- */
- static const struct afs_call_type afs_RXFSFetchData = {
- .deliver = afs_deliver_fs_fetch_data,
- .abort_to_error = afs_abort_to_error,
- .destructor = afs_flat_call_destructor,
- };
- /*
- * fetch data from a file
- */
- int afs_fs_fetch_data(struct afs_server *server,
- struct afs_vnode *vnode,
- off_t offset, size_t length,
- struct page *buffer,
- struct afs_volsync *volsync,
- const struct afs_wait_mode *wait_mode)
- {
- struct afs_call *call;
- __be32 *bp;
- _enter("");
- call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, 120);
- if (!call)
- return -ENOMEM;
- call->reply = vnode;
- call->reply2 = volsync;
- call->reply3 = buffer;
- call->service_id = FS_SERVICE;
- call->port = htons(AFS_FS_PORT);
- /* marshall the parameters */
- bp = call->request;
- bp[0] = htonl(FSFETCHDATA);
- bp[1] = htonl(vnode->fid.vid);
- bp[2] = htonl(vnode->fid.vnode);
- bp[3] = htonl(vnode->fid.unique);
- bp[4] = htonl(offset);
- bp[5] = htonl(length);
- return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
- }
- /*
- * deliver reply data to an FS.GiveUpCallBacks
- */
- static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
- struct sk_buff *skb, bool last)
- {
- _enter(",{%u},%d", skb->len, last);
- if (skb->len > 0)
- return -EBADMSG; /* shouldn't be any reply data */
- return 0;
- }
- /*
- * FS.GiveUpCallBacks operation type
- */
- static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
- .deliver = afs_deliver_fs_give_up_callbacks,
- .abort_to_error = afs_abort_to_error,
- .destructor = afs_flat_call_destructor,
- };
- /*
- * give up a set of callbacks
- * - the callbacks are held in the server->cb_break ring
- */
- int afs_fs_give_up_callbacks(struct afs_server *server,
- const struct afs_wait_mode *wait_mode)
- {
- struct afs_call *call;
- size_t ncallbacks;
- __be32 *bp, *tp;
- int loop;
- ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
- ARRAY_SIZE(server->cb_break));
- _enter("{%zu},", ncallbacks);
- if (ncallbacks == 0)
- return 0;
- if (ncallbacks > AFSCBMAX)
- ncallbacks = AFSCBMAX;
- _debug("break %zu callbacks", ncallbacks);
- call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
- 12 + ncallbacks * 6 * 4, 0);
- if (!call)
- return -ENOMEM;
- call->service_id = FS_SERVICE;
- call->port = htons(AFS_FS_PORT);
- /* marshall the parameters */
- bp = call->request;
- tp = bp + 2 + ncallbacks * 3;
- *bp++ = htonl(FSGIVEUPCALLBACKS);
- *bp++ = htonl(ncallbacks);
- *tp++ = htonl(ncallbacks);
- atomic_sub(ncallbacks, &server->cb_break_n);
- for (loop = ncallbacks; loop > 0; loop--) {
- struct afs_callback *cb =
- &server->cb_break[server->cb_break_tail];
- *bp++ = htonl(cb->fid.vid);
- *bp++ = htonl(cb->fid.vnode);
- *bp++ = htonl(cb->fid.unique);
- *tp++ = htonl(cb->version);
- *tp++ = htonl(cb->expiry);
- *tp++ = htonl(cb->type);
- smp_mb();
- server->cb_break_tail =
- (server->cb_break_tail + 1) &
- (ARRAY_SIZE(server->cb_break) - 1);
- }
- ASSERT(ncallbacks > 0);
- wake_up_nr(&server->cb_break_waitq, ncallbacks);
- return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
- }
|