1 /* AFS File Server client stubs
3 * Copyright (C) 2002, 2007 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 <linux/circ_buf.h>
19 * decode an AFSFetchStatus block
21 static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
22 struct afs_vnode *vnode)
24 const __be32 *bp = *_bp;
27 u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
29 #define EXTRACT(DST) \
31 u32 x = ntohl(*bp++); \
36 vnode->status.if_version = ntohl(*bp++);
37 EXTRACT(vnode->status.type);
38 vnode->status.nlink = ntohl(*bp++);
39 EXTRACT(vnode->status.size);
40 data_version = ntohl(*bp++);
41 EXTRACT(vnode->status.author);
42 EXTRACT(vnode->status.owner);
43 EXTRACT(vnode->status.caller_access); /* call ticket dependent */
44 EXTRACT(vnode->status.anon_access);
45 EXTRACT(vnode->status.mode);
46 vnode->status.parent.vid = vnode->fid.vid;
47 EXTRACT(vnode->status.parent.vnode);
48 EXTRACT(vnode->status.parent.unique);
50 vnode->status.mtime_client = ntohl(*bp++);
51 vnode->status.mtime_server = ntohl(*bp++);
53 bp++; /* sync counter */
54 data_version |= (u64) ntohl(*bp++) << 32;
61 _debug("vnode changed");
62 set_bit(AFS_VNODE_CHANGED, &vnode->flags);
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;
67 vnode->status.mode &= S_IALLUGO;
68 mode = vnode->vfs_inode.i_mode;
70 mode |= vnode->status.mode;
71 vnode->vfs_inode.i_mode = mode;
74 _debug("vnode time %lx, %lx",
75 vnode->status.mtime_client, vnode->status.mtime_server);
76 vnode->vfs_inode.i_ctime.tv_sec = vnode->status.mtime_server;
77 vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime;
78 vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime;
80 if (vnode->status.data_version != data_version) {
81 _debug("vnode modified %llx", data_version);
82 vnode->status.data_version = data_version;
83 set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
84 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
89 * decode an AFSCallBack block
91 static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
93 const __be32 *bp = *_bp;
95 vnode->cb_version = ntohl(*bp++);
96 vnode->cb_expiry = ntohl(*bp++);
97 vnode->cb_type = ntohl(*bp++);
98 vnode->cb_expires = vnode->cb_expiry + get_seconds();
103 * decode an AFSVolSync block
105 static void xdr_decode_AFSVolSync(const __be32 **_bp,
106 struct afs_volsync *volsync)
108 const __be32 *bp = *_bp;
110 volsync->creation = ntohl(*bp++);
120 * deliver reply data to an FS.FetchStatus
122 static int afs_deliver_fs_fetch_status(struct afs_call *call,
123 struct sk_buff *skb, bool last)
127 _enter(",,%u", last);
129 afs_transfer_reply(call, skb);
133 if (call->reply_size != call->reply_max)
136 /* unmarshall the reply once we've received all of it */
138 xdr_decode_AFSFetchStatus(&bp, call->reply);
139 xdr_decode_AFSCallBack(&bp, call->reply);
141 xdr_decode_AFSVolSync(&bp, call->reply2);
143 _leave(" = 0 [done]");
148 * FS.FetchStatus operation type
150 static const struct afs_call_type afs_RXFSFetchStatus = {
151 .deliver = afs_deliver_fs_fetch_status,
152 .abort_to_error = afs_abort_to_error,
153 .destructor = afs_flat_call_destructor,
157 * fetch the status information for a file
159 int afs_fs_fetch_file_status(struct afs_server *server,
160 struct afs_vnode *vnode,
161 struct afs_volsync *volsync,
162 const struct afs_wait_mode *wait_mode)
164 struct afs_call *call;
169 call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120);
174 call->reply2 = volsync;
175 call->service_id = FS_SERVICE;
176 call->port = htons(AFS_FS_PORT);
178 /* marshall the parameters */
180 bp[0] = htonl(FSFETCHSTATUS);
181 bp[1] = htonl(vnode->fid.vid);
182 bp[2] = htonl(vnode->fid.vnode);
183 bp[3] = htonl(vnode->fid.unique);
185 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
189 * deliver reply data to an FS.FetchData
191 static int afs_deliver_fs_fetch_data(struct afs_call *call,
192 struct sk_buff *skb, bool last)
199 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
201 switch (call->unmarshall) {
206 /* extract the returned data length */
208 _debug("extract data length");
209 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
212 case -EAGAIN: return 0;
216 call->count = ntohl(call->tmp);
217 _debug("DATA length: %u", call->count);
218 if (call->count > PAGE_SIZE)
223 if (call->count < PAGE_SIZE) {
224 buffer = kmap_atomic(call->reply3, KM_USER0);
225 memset(buffer + PAGE_SIZE - call->count, 0,
227 kunmap_atomic(buffer, KM_USER0);
230 /* extract the returned data */
232 _debug("extract data");
234 buffer = kmap_atomic(page, KM_USER0);
235 ret = afs_extract_data(call, skb, last, buffer, call->count);
236 kunmap_atomic(buffer, KM_USER0);
239 case -EAGAIN: return 0;
246 /* extract the metadata */
248 ret = afs_extract_data(call, skb, last, call->buffer, 120);
251 case -EAGAIN: return 0;
256 xdr_decode_AFSFetchStatus(&bp, call->reply);
257 xdr_decode_AFSCallBack(&bp, call->reply);
259 xdr_decode_AFSVolSync(&bp, call->reply2);
274 _leave(" = 0 [done]");
279 * FS.FetchData operation type
281 static const struct afs_call_type afs_RXFSFetchData = {
282 .deliver = afs_deliver_fs_fetch_data,
283 .abort_to_error = afs_abort_to_error,
284 .destructor = afs_flat_call_destructor,
288 * fetch data from a file
290 int afs_fs_fetch_data(struct afs_server *server,
291 struct afs_vnode *vnode,
292 off_t offset, size_t length,
294 struct afs_volsync *volsync,
295 const struct afs_wait_mode *wait_mode)
297 struct afs_call *call;
302 call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, 120);
307 call->reply2 = volsync;
308 call->reply3 = buffer;
309 call->service_id = FS_SERVICE;
310 call->port = htons(AFS_FS_PORT);
312 /* marshall the parameters */
314 bp[0] = htonl(FSFETCHDATA);
315 bp[1] = htonl(vnode->fid.vid);
316 bp[2] = htonl(vnode->fid.vnode);
317 bp[3] = htonl(vnode->fid.unique);
318 bp[4] = htonl(offset);
319 bp[5] = htonl(length);
321 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
325 * deliver reply data to an FS.GiveUpCallBacks
327 static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
328 struct sk_buff *skb, bool last)
330 _enter(",{%u},%d", skb->len, last);
333 return -EBADMSG; /* shouldn't be any reply data */
338 * FS.GiveUpCallBacks operation type
340 static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
341 .deliver = afs_deliver_fs_give_up_callbacks,
342 .abort_to_error = afs_abort_to_error,
343 .destructor = afs_flat_call_destructor,
347 * give up a set of callbacks
348 * - the callbacks are held in the server->cb_break ring
350 int afs_fs_give_up_callbacks(struct afs_server *server,
351 const struct afs_wait_mode *wait_mode)
353 struct afs_call *call;
358 ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
359 ARRAY_SIZE(server->cb_break));
361 _enter("{%zu},", ncallbacks);
365 if (ncallbacks > AFSCBMAX)
366 ncallbacks = AFSCBMAX;
368 _debug("break %zu callbacks", ncallbacks);
370 call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
371 12 + ncallbacks * 6 * 4, 0);
375 call->service_id = FS_SERVICE;
376 call->port = htons(AFS_FS_PORT);
378 /* marshall the parameters */
380 tp = bp + 2 + ncallbacks * 3;
381 *bp++ = htonl(FSGIVEUPCALLBACKS);
382 *bp++ = htonl(ncallbacks);
383 *tp++ = htonl(ncallbacks);
385 atomic_sub(ncallbacks, &server->cb_break_n);
386 for (loop = ncallbacks; loop > 0; loop--) {
387 struct afs_callback *cb =
388 &server->cb_break[server->cb_break_tail];
390 *bp++ = htonl(cb->fid.vid);
391 *bp++ = htonl(cb->fid.vnode);
392 *bp++ = htonl(cb->fid.unique);
393 *tp++ = htonl(cb->version);
394 *tp++ = htonl(cb->expiry);
395 *tp++ = htonl(cb->type);
397 server->cb_break_tail =
398 (server->cb_break_tail + 1) &
399 (ARRAY_SIZE(server->cb_break) - 1);
402 ASSERT(ncallbacks > 0);
403 wake_up_nr(&server->cb_break_waitq, ncallbacks);
405 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);