[AFS]: Add security support.
[powerpc.git] / 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 AFSFetchStatus block
20  */
21 static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
22                                       struct afs_vnode *vnode)
23 {
24         const __be32 *bp = *_bp;
25         umode_t mode;
26         u64 data_version;
27         u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
28
29 #define EXTRACT(DST)                            \
30         do {                                    \
31                 u32 x = ntohl(*bp++);           \
32                 changed |= DST - x;             \
33                 DST = x;                        \
34         } while (0)
35
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);
49         bp++; /* seg size */
50         vnode->status.mtime_client = ntohl(*bp++);
51         vnode->status.mtime_server = ntohl(*bp++);
52         bp++; /* group */
53         bp++; /* sync counter */
54         data_version |= (u64) ntohl(*bp++) << 32;
55         bp++; /* spare2 */
56         bp++; /* spare3 */
57         bp++; /* spare4 */
58         *_bp = bp;
59
60         if (changed) {
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;
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         }
73
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;
79
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);
85         }
86 }
87
88 /*
89  * decode an AFSCallBack block
90  */
91 static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
92 {
93         const __be32 *bp = *_bp;
94
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();
99         *_bp = bp;
100 }
101
102 /*
103  * decode an AFSVolSync block
104  */
105 static void xdr_decode_AFSVolSync(const __be32 **_bp,
106                                   struct afs_volsync *volsync)
107 {
108         const __be32 *bp = *_bp;
109
110         volsync->creation = ntohl(*bp++);
111         bp++; /* spare2 */
112         bp++; /* spare3 */
113         bp++; /* spare4 */
114         bp++; /* spare5 */
115         bp++; /* spare6 */
116         *_bp = bp;
117 }
118
119 /*
120  * deliver reply data to an FS.FetchStatus
121  */
122 static int afs_deliver_fs_fetch_status(struct afs_call *call,
123                                        struct sk_buff *skb, bool last)
124 {
125         const __be32 *bp;
126
127         _enter(",,%u", last);
128
129         afs_transfer_reply(call, skb);
130         if (!last)
131                 return 0;
132
133         if (call->reply_size != call->reply_max)
134                 return -EBADMSG;
135
136         /* unmarshall the reply once we've received all of it */
137         bp = call->buffer;
138         xdr_decode_AFSFetchStatus(&bp, call->reply);
139         xdr_decode_AFSCallBack(&bp, call->reply);
140         if (call->reply2)
141                 xdr_decode_AFSVolSync(&bp, call->reply2);
142
143         _leave(" = 0 [done]");
144         return 0;
145 }
146
147 /*
148  * FS.FetchStatus operation type
149  */
150 static const struct afs_call_type afs_RXFSFetchStatus = {
151         .name           = "FS.FetchStatus",
152         .deliver        = afs_deliver_fs_fetch_status,
153         .abort_to_error = afs_abort_to_error,
154         .destructor     = afs_flat_call_destructor,
155 };
156
157 /*
158  * fetch the status information for a file
159  */
160 int afs_fs_fetch_file_status(struct afs_server *server,
161                              struct key *key,
162                              struct afs_vnode *vnode,
163                              struct afs_volsync *volsync,
164                              const struct afs_wait_mode *wait_mode)
165 {
166         struct afs_call *call;
167         __be32 *bp;
168
169         _enter(",%x,,,", key_serial(key));
170
171         call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120);
172         if (!call)
173                 return -ENOMEM;
174
175         call->key = key;
176         call->reply = vnode;
177         call->reply2 = volsync;
178         call->service_id = FS_SERVICE;
179         call->port = htons(AFS_FS_PORT);
180
181         /* marshall the parameters */
182         bp = call->request;
183         bp[0] = htonl(FSFETCHSTATUS);
184         bp[1] = htonl(vnode->fid.vid);
185         bp[2] = htonl(vnode->fid.vnode);
186         bp[3] = htonl(vnode->fid.unique);
187
188         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
189 }
190
191 /*
192  * deliver reply data to an FS.FetchData
193  */
194 static int afs_deliver_fs_fetch_data(struct afs_call *call,
195                                      struct sk_buff *skb, bool last)
196 {
197         const __be32 *bp;
198         struct page *page;
199         void *buffer;
200         int ret;
201
202         _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
203
204         switch (call->unmarshall) {
205         case 0:
206                 call->offset = 0;
207                 call->unmarshall++;
208
209                 /* extract the returned data length */
210         case 1:
211                 _debug("extract data length");
212                 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
213                 switch (ret) {
214                 case 0:         break;
215                 case -EAGAIN:   return 0;
216                 default:        return ret;
217                 }
218
219                 call->count = ntohl(call->tmp);
220                 _debug("DATA length: %u", call->count);
221                 if (call->count > PAGE_SIZE)
222                         return -EBADMSG;
223                 call->offset = 0;
224                 call->unmarshall++;
225
226                 if (call->count < PAGE_SIZE) {
227                         buffer = kmap_atomic(call->reply3, KM_USER0);
228                         memset(buffer + PAGE_SIZE - call->count, 0,
229                                call->count);
230                         kunmap_atomic(buffer, KM_USER0);
231                 }
232
233                 /* extract the returned data */
234         case 2:
235                 _debug("extract data");
236                 page = call->reply3;
237                 buffer = kmap_atomic(page, KM_USER0);
238                 ret = afs_extract_data(call, skb, last, buffer, call->count);
239                 kunmap_atomic(buffer, KM_USER0);
240                 switch (ret) {
241                 case 0:         break;
242                 case -EAGAIN:   return 0;
243                 default:        return ret;
244                 }
245
246                 call->offset = 0;
247                 call->unmarshall++;
248
249                 /* extract the metadata */
250         case 3:
251                 ret = afs_extract_data(call, skb, last, call->buffer, 120);
252                 switch (ret) {
253                 case 0:         break;
254                 case -EAGAIN:   return 0;
255                 default:        return ret;
256                 }
257
258                 bp = call->buffer;
259                 xdr_decode_AFSFetchStatus(&bp, call->reply);
260                 xdr_decode_AFSCallBack(&bp, call->reply);
261                 if (call->reply2)
262                         xdr_decode_AFSVolSync(&bp, call->reply2);
263
264                 call->offset = 0;
265                 call->unmarshall++;
266
267         case 4:
268                 _debug("trailer");
269                 if (skb->len != 0)
270                         return -EBADMSG;
271                 break;
272         }
273
274         if (!last)
275                 return 0;
276
277         _leave(" = 0 [done]");
278         return 0;
279 }
280
281 /*
282  * FS.FetchData operation type
283  */
284 static const struct afs_call_type afs_RXFSFetchData = {
285         .name           = "FS.FetchData",
286         .deliver        = afs_deliver_fs_fetch_data,
287         .abort_to_error = afs_abort_to_error,
288         .destructor     = afs_flat_call_destructor,
289 };
290
291 /*
292  * fetch data from a file
293  */
294 int afs_fs_fetch_data(struct afs_server *server,
295                       struct key *key,
296                       struct afs_vnode *vnode,
297                       off_t offset, size_t length,
298                       struct page *buffer,
299                       struct afs_volsync *volsync,
300                       const struct afs_wait_mode *wait_mode)
301 {
302         struct afs_call *call;
303         __be32 *bp;
304
305         _enter("");
306
307         call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, 120);
308         if (!call)
309                 return -ENOMEM;
310
311         call->key = key;
312         call->reply = vnode;
313         call->reply2 = volsync;
314         call->reply3 = buffer;
315         call->service_id = FS_SERVICE;
316         call->port = htons(AFS_FS_PORT);
317
318         /* marshall the parameters */
319         bp = call->request;
320         bp[0] = htonl(FSFETCHDATA);
321         bp[1] = htonl(vnode->fid.vid);
322         bp[2] = htonl(vnode->fid.vnode);
323         bp[3] = htonl(vnode->fid.unique);
324         bp[4] = htonl(offset);
325         bp[5] = htonl(length);
326
327         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
328 }
329
330 /*
331  * deliver reply data to an FS.GiveUpCallBacks
332  */
333 static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
334                                             struct sk_buff *skb, bool last)
335 {
336         _enter(",{%u},%d", skb->len, last);
337
338         if (skb->len > 0)
339                 return -EBADMSG; /* shouldn't be any reply data */
340         return 0;
341 }
342
343 /*
344  * FS.GiveUpCallBacks operation type
345  */
346 static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
347         .name           = "FS.GiveUpCallBacks",
348         .deliver        = afs_deliver_fs_give_up_callbacks,
349         .abort_to_error = afs_abort_to_error,
350         .destructor     = afs_flat_call_destructor,
351 };
352
353 /*
354  * give up a set of callbacks
355  * - the callbacks are held in the server->cb_break ring
356  */
357 int afs_fs_give_up_callbacks(struct afs_server *server,
358                              const struct afs_wait_mode *wait_mode)
359 {
360         struct afs_call *call;
361         size_t ncallbacks;
362         __be32 *bp, *tp;
363         int loop;
364
365         ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
366                               ARRAY_SIZE(server->cb_break));
367
368         _enter("{%zu},", ncallbacks);
369
370         if (ncallbacks == 0)
371                 return 0;
372         if (ncallbacks > AFSCBMAX)
373                 ncallbacks = AFSCBMAX;
374
375         _debug("break %zu callbacks", ncallbacks);
376
377         call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
378                                    12 + ncallbacks * 6 * 4, 0);
379         if (!call)
380                 return -ENOMEM;
381
382         call->service_id = FS_SERVICE;
383         call->port = htons(AFS_FS_PORT);
384
385         /* marshall the parameters */
386         bp = call->request;
387         tp = bp + 2 + ncallbacks * 3;
388         *bp++ = htonl(FSGIVEUPCALLBACKS);
389         *bp++ = htonl(ncallbacks);
390         *tp++ = htonl(ncallbacks);
391
392         atomic_sub(ncallbacks, &server->cb_break_n);
393         for (loop = ncallbacks; loop > 0; loop--) {
394                 struct afs_callback *cb =
395                         &server->cb_break[server->cb_break_tail];
396
397                 *bp++ = htonl(cb->fid.vid);
398                 *bp++ = htonl(cb->fid.vnode);
399                 *bp++ = htonl(cb->fid.unique);
400                 *tp++ = htonl(cb->version);
401                 *tp++ = htonl(cb->expiry);
402                 *tp++ = htonl(cb->type);
403                 smp_mb();
404                 server->cb_break_tail =
405                         (server->cb_break_tail + 1) &
406                         (ARRAY_SIZE(server->cb_break) - 1);
407         }
408
409         ASSERT(ncallbacks > 0);
410         wake_up_nr(&server->cb_break_waitq, ncallbacks);
411
412         return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
413 }