Blame view

fs/coda/upcall.c 22.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * Mostly platform independent upcall operations to Venus:
   *  -- upcalls
   *  -- upcall routines
   *
   * Linux 2.0 version
   * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>, 
   * Michael Callahan <callahan@maths.ox.ac.uk> 
   * 
   * Redone for Linux 2.1
   * Copyright (C) 1997 Carnegie Mellon University
   *
   * Carnegie Mellon University encourages users of this code to contribute
   * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
   */
  
  #include <asm/system.h>
  #include <linux/signal.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
19
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
25
26
27
28
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/mm.h>
  #include <linux/time.h>
  #include <linux/fs.h>
  #include <linux/file.h>
  #include <linux/stat.h>
  #include <linux/errno.h>
  #include <linux/string.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
29
  #include <linux/slab.h>
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
30
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
  #include <asm/uaccess.h>
  #include <linux/vmalloc.h>
  #include <linux/vfs.h>
  
  #include <linux/coda.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  #include <linux/coda_psdev.h>
31a203df9   Al Viro   take coda-private...
37
38
  #include "coda_linux.h"
  #include "coda_cache.h"
3cf01f28c   Jan Harkes   coda: remove stat...
39
40
  
  #include "coda_int.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41

a1b0aa876   Jan Harkes   coda: remove stru...
42
  static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
49
50
51
52
53
54
  		       union inputArgs *buffer);
  
  static void *alloc_upcall(int opcode, int size)
  {
  	union inputArgs *inp;
  
  	CODA_ALLOC(inp, union inputArgs *, size);
          if (!inp)
  		return ERR_PTR(-ENOMEM);
  
          inp->ih.opcode = opcode;
  	inp->ih.pid = current->pid;
a47afb0f9   Pavel Emelianov   pid namespaces: r...
55
  	inp->ih.pgid = task_pgrp_nr(current);
97b7702cd   David Howells   CRED: Wrap task c...
56
  	inp->ih.uid = current_fsuid();
de0ca06a9   Adrian Bunk   coda: remove CODA...
57

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  	return (void*)inp;
  }
  
  #define UPARG(op)\
  do {\
  	inp = (union inputArgs *)alloc_upcall(op, insize); \
          if (IS_ERR(inp)) { return PTR_ERR(inp); }\
          outp = (union outputArgs *)(inp); \
          outsize = insize; \
  } while (0)
  
  #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
  #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
  #define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
  
  
  /* the upcalls */
  int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
  
          insize = SIZE(root);
          UPARG(CODA_ROOT);
a1b0aa876   Jan Harkes   coda: remove stru...
83
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
970648eb0   Jan Harkes   coda: ignore retu...
84
  	if (!error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  		*fidp = outp->coda_root.VFid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  
  	CODA_FREE(inp, insize);
  	return error;
  }
  
  int venus_getattr(struct super_block *sb, struct CodaFid *fid, 
  		     struct coda_vattr *attr) 
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
  
          insize = SIZE(getattr); 
  	UPARG(CODA_GETATTR);
          inp->coda_getattr.VFid = *fid;
a1b0aa876   Jan Harkes   coda: remove stru...
101
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
970648eb0   Jan Harkes   coda: ignore retu...
102
103
  	if (!error)
  		*attr = outp->coda_getattr.attr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  
  	CODA_FREE(inp, insize);
          return error;
  }
  
  int venus_setattr(struct super_block *sb, struct CodaFid *fid, 
  		  struct coda_vattr *vattr)
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
  	
  	insize = SIZE(setattr);
  	UPARG(CODA_SETATTR);
  
          inp->coda_setattr.VFid = *fid;
  	inp->coda_setattr.attr = *vattr;
a1b0aa876   Jan Harkes   coda: remove stru...
121
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  
          CODA_FREE(inp, insize);
          return error;
  }
  
  int venus_lookup(struct super_block *sb, struct CodaFid *fid, 
  		    const char *name, int length, int * type, 
  		    struct CodaFid *resfid)
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
  	int offset;
  
  	offset = INSIZE(lookup);
          insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
  	UPARG(CODA_LOOKUP);
  
          inp->coda_lookup.VFid = *fid;
  	inp->coda_lookup.name = offset;
  	inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
          /* send Venus a null terminated string */
          memcpy((char *)(inp) + offset, name, length);
          *((char *)inp + offset + length) = '\0';
a1b0aa876   Jan Harkes   coda: remove stru...
146
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
970648eb0   Jan Harkes   coda: ignore retu...
147
148
149
150
  	if (!error) {
  		*resfid = outp->coda_lookup.VFid;
  		*type = outp->coda_lookup.vtype;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
  
  	CODA_FREE(inp, insize);
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
d3fec424b   Jan Harkes   coda: remove CODA...
156
  		vuid_t uid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
  {
  	union inputArgs *inp;
  	union outputArgs *outp;
  	int insize, outsize, error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
  	
  	insize = SIZE(release);
  	UPARG(CODA_CLOSE);
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  	inp->ih.uid = uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
          inp->coda_close.VFid = *fid;
          inp->coda_close.flags = flags;
a1b0aa876   Jan Harkes   coda: remove stru...
168
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  
  	CODA_FREE(inp, insize);
          return error;
  }
  
  int venus_open(struct super_block *sb, struct CodaFid *fid,
  		  int flags, struct file **fh)
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
         
  	insize = SIZE(open_by_fd);
  	UPARG(CODA_OPEN_BY_FD);
38c2e4370   Jan Harkes   coda: do not grab...
183
184
  	inp->coda_open_by_fd.VFid = *fid;
  	inp->coda_open_by_fd.flags = flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185

a1b0aa876   Jan Harkes   coda: remove stru...
186
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
38c2e4370   Jan Harkes   coda: do not grab...
187
188
  	if (!error)
  		*fh = outp->coda_open_by_fd.fh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  
  	CODA_FREE(inp, insize);
  	return error;
  }	
  
  int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, 
  		   const char *name, int length, 
  		   struct CodaFid *newfid, struct coda_vattr *attrs)
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
          int offset;
  
  	offset = INSIZE(mkdir);
  	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
  	UPARG(CODA_MKDIR);
  
          inp->coda_mkdir.VFid = *dirfid;
          inp->coda_mkdir.attr = *attrs;
  	inp->coda_mkdir.name = offset;
          /* Venus must get null terminated string */
          memcpy((char *)(inp) + offset, name, length);
          *((char *)inp + offset + length) = '\0';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213

a1b0aa876   Jan Harkes   coda: remove stru...
214
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
970648eb0   Jan Harkes   coda: ignore retu...
215
216
217
218
  	if (!error) {
  		*attrs = outp->coda_mkdir.attr;
  		*newfid = outp->coda_mkdir.VFid;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  
  	CODA_FREE(inp, insize);
  	return error;        
  }
  
  
  int venus_rename(struct super_block *sb, struct CodaFid *old_fid, 
  		 struct CodaFid *new_fid, size_t old_length, 
  		 size_t new_length, const char *old_name, 
  		 const char *new_name)
  {
  	union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error; 
  	int offset, s;
  	
  	offset = INSIZE(rename);
  	insize = max_t(unsigned int, offset + new_length + old_length + 8,
  		     OUTSIZE(rename)); 
   	UPARG(CODA_RENAME);
  
          inp->coda_rename.sourceFid = *old_fid;
          inp->coda_rename.destFid =  *new_fid;
          inp->coda_rename.srcname = offset;
  
          /* Venus must receive an null terminated string */
          s = ( old_length & ~0x3) +4; /* round up to word boundary */
          memcpy((char *)(inp) + offset, old_name, old_length);
          *((char *)inp + offset + old_length) = '\0';
  
          /* another null terminated string for Venus */
          offset += s;
          inp->coda_rename.destname = offset;
          s = ( new_length & ~0x3) +4; /* round up to word boundary */
          memcpy((char *)(inp) + offset, new_name, new_length);
          *((char *)inp + offset + new_length) = '\0';
a1b0aa876   Jan Harkes   coda: remove stru...
255
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  
  	CODA_FREE(inp, insize);
  	return error;
  }
  
  int venus_create(struct super_block *sb, struct CodaFid *dirfid, 
  		 const char *name, int length, int excl, int mode,
  		 struct CodaFid *newfid, struct coda_vattr *attrs) 
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
          int offset;
  
          offset = INSIZE(create);
  	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
  	UPARG(CODA_CREATE);
  
          inp->coda_create.VFid = *dirfid;
          inp->coda_create.attr.va_mode = mode;
  	inp->coda_create.excl = excl;
          inp->coda_create.mode = mode;
          inp->coda_create.name = offset;
  
          /* Venus must get null terminated string */
          memcpy((char *)(inp) + offset, name, length);
          *((char *)inp + offset + length) = '\0';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

a1b0aa876   Jan Harkes   coda: remove stru...
284
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
970648eb0   Jan Harkes   coda: ignore retu...
285
286
287
288
  	if (!error) {
  		*attrs = outp->coda_create.attr;
  		*newfid = outp->coda_create.VFid;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  
  	CODA_FREE(inp, insize);
  	return error;        
  }
  
  int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, 
  		    const char *name, int length)
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
          int offset;
  
          offset = INSIZE(rmdir);
  	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
  	UPARG(CODA_RMDIR);
  
          inp->coda_rmdir.VFid = *dirfid;
          inp->coda_rmdir.name = offset;
          memcpy((char *)(inp) + offset, name, length);
  	*((char *)inp + offset + length) = '\0';
a1b0aa876   Jan Harkes   coda: remove stru...
310
311
  
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  
  	CODA_FREE(inp, insize);
  	return error;
  }
  
  int venus_remove(struct super_block *sb, struct CodaFid *dirfid, 
  		    const char *name, int length)
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int error=0, insize, outsize, offset;
  
          offset = INSIZE(remove);
  	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
  	UPARG(CODA_REMOVE);
  
          inp->coda_remove.VFid = *dirfid;
          inp->coda_remove.name = offset;
          memcpy((char *)(inp) + offset, name, length);
  	*((char *)inp + offset + length) = '\0';
a1b0aa876   Jan Harkes   coda: remove stru...
332
333
  
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  
  	CODA_FREE(inp, insize);
  	return error;
  }
  
  int venus_readlink(struct super_block *sb, struct CodaFid *fid, 
  		      char *buffer, int *length)
  { 
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
          int retlen;
          char *result;
          
  	insize = max_t(unsigned int,
  		     INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
  	UPARG(CODA_READLINK);
  
          inp->coda_readlink.VFid = *fid;
970648eb0   Jan Harkes   coda: ignore retu...
353

a1b0aa876   Jan Harkes   coda: remove stru...
354
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
970648eb0   Jan Harkes   coda: ignore retu...
355
356
  	if (!error) {
  		retlen = outp->coda_readlink.count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  		if ( retlen > *length )
970648eb0   Jan Harkes   coda: ignore retu...
358
  			retlen = *length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
  		*length = retlen;
  		result =  (char *)outp + (long)outp->coda_readlink.data;
  		memcpy(buffer, result, retlen);
  		*(buffer + retlen) = '\0';
  	}
970648eb0   Jan Harkes   coda: ignore retu...
364

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
          CODA_FREE(inp, insize);
          return error;
  }
  
  
  
  int venus_link(struct super_block *sb, struct CodaFid *fid, 
  		  struct CodaFid *dirfid, const char *name, int len )
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
          int offset;
  
  	offset = INSIZE(link);
  	insize = max_t(unsigned int, offset  + len + 1, OUTSIZE(link));
          UPARG(CODA_LINK);
  
          inp->coda_link.sourceFid = *fid;
          inp->coda_link.destFid = *dirfid;
          inp->coda_link.tname = offset;
  
          /* make sure strings are null terminated */
          memcpy((char *)(inp) + offset, name, len);
          *((char *)inp + offset + len) = '\0';
a1b0aa876   Jan Harkes   coda: remove stru...
390
391
  
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
  
  	CODA_FREE(inp, insize);
          return error;
  }
  
  int venus_symlink(struct super_block *sb, struct CodaFid *fid,
  		     const char *name, int len,
  		     const char *symname, int symlen)
  {
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
          int offset, s;
  
          offset = INSIZE(symlink);
  	insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
  	UPARG(CODA_SYMLINK);
          
          /*        inp->coda_symlink.attr = *tva; XXXXXX */ 
          inp->coda_symlink.VFid = *fid;
  
  	/* Round up to word boundary and null terminate */
          inp->coda_symlink.srcname = offset;
          s = ( symlen  & ~0x3 ) + 4; 
          memcpy((char *)(inp) + offset, symname, symlen);
          *((char *)inp + offset + symlen) = '\0';
          
  	/* Round up to word boundary and null terminate */
          offset += s;
          inp->coda_symlink.tname = offset;
          s = (len & ~0x3) + 4;
          memcpy((char *)(inp) + offset, name, len);
          *((char *)inp + offset + len) = '\0';
a1b0aa876   Jan Harkes   coda: remove stru...
425
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
429
430
431
432
433
434
435
436
437
438
  
  	CODA_FREE(inp, insize);
          return error;
  }
  
  int venus_fsync(struct super_block *sb, struct CodaFid *fid)
  {
          union inputArgs *inp;
          union outputArgs *outp; 
  	int insize, outsize, error;
  	
  	insize=SIZE(fsync);
  	UPARG(CODA_FSYNC);
a1b0aa876   Jan Harkes   coda: remove stru...
439
440
441
  	inp->coda_fsync.VFid = *fid;
  	error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs),
  			    &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  
  	CODA_FREE(inp, insize);
  	return error;
  }
  
  int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
  {
          union inputArgs *inp;
          union outputArgs *outp; 
  	int insize, outsize, error;
  
  	insize = SIZE(access);
  	UPARG(CODA_ACCESS);
  
          inp->coda_access.VFid = *fid;
          inp->coda_access.flags = mask;
a1b0aa876   Jan Harkes   coda: remove stru...
458
  	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  
  	CODA_FREE(inp, insize);
  	return error;
  }
  
  
  int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
  		 unsigned int cmd, struct PioctlData *data)
  {
          union inputArgs *inp;
          union outputArgs *outp;  
  	int insize, outsize, error;
  	int iocsize;
  
  	insize = VC_MAXMSGSIZE;
  	UPARG(CODA_IOCTL);
  
          /* build packet for Venus */
          if (data->vi.in_size > VC_MAXDATASIZE) {
  		error = -EINVAL;
  		goto exit;
          }
  
          if (data->vi.out_size > VC_MAXDATASIZE) {
  		error = -EINVAL;
  		goto exit;
  	}
  
          inp->coda_ioctl.VFid = *fid;
      
          /* the cmd field was mutated by increasing its size field to
           * reflect the path and follow args. We need to subtract that
           * out before sending the command to Venus.  */
          inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));	
          iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
          inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<	16;	
      
          /* in->coda_ioctl.rwflag = flag; */
          inp->coda_ioctl.len = data->vi.in_size;
          inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
       
          /* get the data out of user space */
          if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
  			    data->vi.in, data->vi.in_size) ) {
  		error = -EINVAL;
  	        goto exit;
  	}
a1b0aa876   Jan Harkes   coda: remove stru...
506
507
  	error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
  			    &outsize, inp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
          if (error) {
  	        printk("coda_pioctl: Venus returns: %d for %s
  ", 
  		       error, coda_f2s(fid));
  		goto exit; 
  	}
  
  	if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
  		error = -EINVAL;
  		goto exit;
  	}
          
  	/* Copy out the OUT buffer. */
          if (outp->coda_ioctl.len > data->vi.out_size) {
  		error = -EINVAL;
  		goto exit;
          }
  
  	/* Copy out the OUT buffer. */
  	if (copy_to_user(data->vi.out,
  			 (char *)outp + (long)outp->coda_ioctl.data,
  			 outp->coda_ioctl.len)) {
  		error = -EFAULT;
  		goto exit;
  	}
  
   exit:
  	CODA_FREE(inp, insize);
  	return error;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
538
  int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
542
543
544
545
  { 
          union inputArgs *inp;
          union outputArgs *outp;
          int insize, outsize, error;
          
  	insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
  	UPARG(CODA_STATFS);
a1b0aa876   Jan Harkes   coda: remove stru...
546
  	error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
970648eb0   Jan Harkes   coda: ignore retu...
547
  	if (!error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
550
551
552
  		sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
  		sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
  		sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
  		sfs->f_files  = outp->coda_statfs.stat.f_files;
  		sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
555
556
557
558
559
560
  	}
  
          CODA_FREE(inp, insize);
          return error;
  }
  
  /*
   * coda_upcall and coda_downcall routines.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
   */
5f47c7eac   Al Viro   coda breakage
562
  static void coda_block_signals(sigset_t *old)
d9664c95a   Jan Harkes   coda: block signa...
563
564
565
566
567
568
569
570
571
572
573
574
  {
  	spin_lock_irq(&current->sighand->siglock);
  	*old = current->blocked;
  
  	sigfillset(&current->blocked);
  	sigdelset(&current->blocked, SIGKILL);
  	sigdelset(&current->blocked, SIGSTOP);
  	sigdelset(&current->blocked, SIGINT);
  
  	recalc_sigpending();
  	spin_unlock_irq(&current->sighand->siglock);
  }
5f47c7eac   Al Viro   coda breakage
575
  static void coda_unblock_signals(sigset_t *old)
d9664c95a   Jan Harkes   coda: block signa...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  {
  	spin_lock_irq(&current->sighand->siglock);
  	current->blocked = *old;
  	recalc_sigpending();
  	spin_unlock_irq(&current->sighand->siglock);
  }
  
  /* Don't allow signals to interrupt the following upcalls before venus
   * has seen them,
   * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
   * - CODA_STORE				(to avoid data loss)
   */
  #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
  			       (((r)->uc_opcode != CODA_CLOSE && \
  				 (r)->uc_opcode != CODA_STORE && \
  				 (r)->uc_opcode != CODA_RELEASE) || \
4aeefdc69   Jens Axboe   coda: fixup clash...
592
  				(r)->uc_flags & CODA_REQ_READ))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593

da47c19e5   Yoshihisa Abe   Coda: replace BKL...
594
595
  static inline void coda_waitfor_upcall(struct venus_comm *vcp,
  				       struct upc_req *req)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
  {
  	DECLARE_WAITQUEUE(wait, current);
d9664c95a   Jan Harkes   coda: block signa...
598
599
600
  	unsigned long timeout = jiffies + coda_timeout * HZ;
  	sigset_t old;
  	int blocked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601

5f47c7eac   Al Viro   coda breakage
602
  	coda_block_signals(&old);
d9664c95a   Jan Harkes   coda: block signa...
603
  	blocked = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604

d9664c95a   Jan Harkes   coda: block signa...
605
  	add_wait_queue(&req->uc_sleep, &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  	for (;;) {
d9664c95a   Jan Harkes   coda: block signa...
607
  		if (CODA_INTERRUPTIBLE(req))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
  			set_current_state(TASK_INTERRUPTIBLE);
  		else
  			set_current_state(TASK_UNINTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  		/* got a reply */
4aeefdc69   Jens Axboe   coda: fixup clash...
612
  		if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  			break;
d9664c95a   Jan Harkes   coda: block signa...
614
615
616
  		if (blocked && time_after(jiffies, timeout) &&
  		    CODA_INTERRUPTIBLE(req))
  		{
5f47c7eac   Al Viro   coda breakage
617
  			coda_unblock_signals(&old);
d9664c95a   Jan Harkes   coda: block signa...
618
  			blocked = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
  		}
d9664c95a   Jan Harkes   coda: block signa...
620
621
622
623
624
  
  		if (signal_pending(current)) {
  			list_del(&req->uc_chain);
  			break;
  		}
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
625
  		mutex_unlock(&vcp->vc_mutex);
d9664c95a   Jan Harkes   coda: block signa...
626
627
628
629
  		if (blocked)
  			schedule_timeout(HZ);
  		else
  			schedule();
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
630
  		mutex_lock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
  	}
d9664c95a   Jan Harkes   coda: block signa...
632
  	if (blocked)
5f47c7eac   Al Viro   coda breakage
633
  		coda_unblock_signals(&old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634

d9664c95a   Jan Harkes   coda: block signa...
635
636
  	remove_wait_queue(&req->uc_sleep, &wait);
  	set_current_state(TASK_RUNNING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
  }
a1b0aa876   Jan Harkes   coda: remove stru...
638
639
  /*
   * coda_upcall will return an error in the case of
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
644
645
   * failed communication with Venus _or_ will peek at Venus
   * reply and return Venus' error.
   *
   * As venus has 2 types of errors, normal errors (positive) and internal
   * errors (negative), normal errors are negated, while internal errors
   * are all mapped to -EINTR, while showing a nice warning message. (jh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
   */
a1b0aa876   Jan Harkes   coda: remove stru...
647
  static int coda_upcall(struct venus_comm *vcp,
fe71b5f38   Jan Harkes   coda: cleanup for...
648
649
  		       int inSize, int *outSize,
  		       union inputArgs *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  	union outputArgs *out;
fe71b5f38   Jan Harkes   coda: cleanup for...
652
  	union inputArgs *sig_inputArgs;
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
653
654
  	struct upc_req *req = NULL, *sig_req;
  	int error;
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
655
  	mutex_lock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656

a1b0aa876   Jan Harkes   coda: remove stru...
657
  	if (!vcp->vc_inuse) {
fe71b5f38   Jan Harkes   coda: cleanup for...
658
659
  		printk(KERN_NOTICE "coda: Venus dead, not sending upcall
  ");
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
660
661
  		error = -ENXIO;
  		goto exit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
  	}
  
  	/* Format the request message. */
37461e195   Jan Harkes   coda: replace upc...
665
  	req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
666
667
668
669
  	if (!req) {
  		error = -ENOMEM;
  		goto exit;
  	}
fe71b5f38   Jan Harkes   coda: cleanup for...
670

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
674
675
  	req->uc_data = (void *)buffer;
  	req->uc_flags = 0;
  	req->uc_inSize = inSize;
  	req->uc_outSize = *outSize ? *outSize : inSize;
  	req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
a1b0aa876   Jan Harkes   coda: remove stru...
676
  	req->uc_unique = ++vcp->vc_seq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  	init_waitqueue_head(&req->uc_sleep);
fe71b5f38   Jan Harkes   coda: cleanup for...
678

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
682
  	/* Fill in the common input args. */
  	((union inputArgs *)buffer)->ih.unique = req->uc_unique;
  
  	/* Append msg to pending queue and poke Venus. */
a1b0aa876   Jan Harkes   coda: remove stru...
683
  	list_add_tail(&req->uc_chain, &vcp->vc_pending);
fe71b5f38   Jan Harkes   coda: cleanup for...
684

a1b0aa876   Jan Harkes   coda: remove stru...
685
  	wake_up_interruptible(&vcp->vc_waitq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
690
691
692
693
694
695
  	/* We can be interrupted while we wait for Venus to process
  	 * our request.  If the interrupt occurs before Venus has read
  	 * the request, we dequeue and return. If it occurs after the
  	 * read but before the reply, we dequeue, send a signal
  	 * message, and return. If it occurs after the reply we ignore
  	 * it. In no case do we want to restart the syscall.  If it
  	 * was interrupted by a venus shutdown (psdev_close), return
  	 * ENODEV.  */
  
  	/* Go to sleep.  Wake up on signals only after the timeout. */
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
696
  	coda_waitfor_upcall(vcp, req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697

fe71b5f38   Jan Harkes   coda: cleanup for...
698
  	/* Op went through, interrupt or not... */
4aeefdc69   Jens Axboe   coda: fixup clash...
699
  	if (req->uc_flags & CODA_REQ_WRITE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
  		out = (union outputArgs *)req->uc_data;
  		/* here we map positive Venus errors to kernel errors */
  		error = -out->oh.result;
  		*outSize = req->uc_outSize;
  		goto exit;
fe71b5f38   Jan Harkes   coda: cleanup for...
705
706
707
  	}
  
  	error = -EINTR;
4aeefdc69   Jens Axboe   coda: fixup clash...
708
  	if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
fe71b5f38   Jan Harkes   coda: cleanup for...
709
710
  		printk(KERN_WARNING "coda: Unexpected interruption.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  		goto exit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
  	}
fe71b5f38   Jan Harkes   coda: cleanup for...
713
  	/* Interrupted before venus read it. */
4aeefdc69   Jens Axboe   coda: fixup clash...
714
  	if (!(req->uc_flags & CODA_REQ_READ))
fe71b5f38   Jan Harkes   coda: cleanup for...
715
716
717
  		goto exit;
  
  	/* Venus saw the upcall, make sure we can send interrupt signal */
a1b0aa876   Jan Harkes   coda: remove stru...
718
  	if (!vcp->vc_inuse) {
fe71b5f38   Jan Harkes   coda: cleanup for...
719
720
721
722
723
724
  		printk(KERN_INFO "coda: Venus dead, not sending signal.
  ");
  		goto exit;
  	}
  
  	error = -ENOMEM;
37461e195   Jan Harkes   coda: replace upc...
725
  	sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
fe71b5f38   Jan Harkes   coda: cleanup for...
726
727
728
729
  	if (!sig_req) goto exit;
  
  	CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
  	if (!sig_req->uc_data) {
37461e195   Jan Harkes   coda: replace upc...
730
  		kfree(sig_req);
fe71b5f38   Jan Harkes   coda: cleanup for...
731
732
733
734
735
736
737
  		goto exit;
  	}
  
  	error = -EINTR;
  	sig_inputArgs = (union inputArgs *)sig_req->uc_data;
  	sig_inputArgs->ih.opcode = CODA_SIGNAL;
  	sig_inputArgs->ih.unique = req->uc_unique;
4aeefdc69   Jens Axboe   coda: fixup clash...
738
  	sig_req->uc_flags = CODA_REQ_ASYNC;
fe71b5f38   Jan Harkes   coda: cleanup for...
739
740
741
742
743
744
  	sig_req->uc_opcode = sig_inputArgs->ih.opcode;
  	sig_req->uc_unique = sig_inputArgs->ih.unique;
  	sig_req->uc_inSize = sizeof(struct coda_in_hdr);
  	sig_req->uc_outSize = sizeof(struct coda_in_hdr);
  
  	/* insert at head of queue! */
a1b0aa876   Jan Harkes   coda: remove stru...
745
746
  	list_add(&(sig_req->uc_chain), &vcp->vc_pending);
  	wake_up_interruptible(&vcp->vc_waitq);
fe71b5f38   Jan Harkes   coda: cleanup for...
747
748
  
  exit:
37461e195   Jan Harkes   coda: replace upc...
749
  	kfree(req);
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
750
  	mutex_unlock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  	return error;
  }
  
  /*  
      The statements below are part of the Coda opportunistic
      programming -- taken from the Mach/BSD kernel code for Coda. 
      You don't get correct semantics by stating what needs to be
      done without guaranteeing the invariants needed for it to happen.
      When will be have time to find out what exactly is going on?  (pjb)
  */
  
  
  /* 
   * There are 7 cases where cache invalidations occur.  The semantics
   *  of each is listed here:
   *
   * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
   * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
   *                  This call is a result of token expiration.
   *
   * The next arise as the result of callbacks on a file or directory.
   * CODA_ZAPFILE   -- flush the cached attributes for a file.
  
   * CODA_ZAPDIR    -- flush the attributes for the dir and
   *                  force a new lookup for all the children
                      of this dir.
  
   *
   * The next is a result of Venus detecting an inconsistent file.
   * CODA_PURGEFID  -- flush the attribute for the file
   *                  purge it and its children from the dcache
   *
   * The last  allows Venus to replace local fids with global ones
   * during reintegration.
   *
   * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
787
  int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  {
5fd31e9a6   Jan Harkes   coda: cleanup dow...
789
  	struct inode *inode = NULL;
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
790
  	struct CodaFid *fid = NULL, *newfid;
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
791
  	struct super_block *sb;
5fd31e9a6   Jan Harkes   coda: cleanup dow...
792

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
  	/* Handle invalidation requests. */
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
794
  	mutex_lock(&vcp->vc_mutex);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
795
796
797
  	sb = vcp->vc_sb;
  	if (!sb || !sb->s_root)
  		goto unlock_out;
5fd31e9a6   Jan Harkes   coda: cleanup dow...
798
799
800
801
802
803
  
  	switch (opcode) {
  	case CODA_FLUSH:
  		coda_cache_clear_all(sb);
  		shrink_dcache_sb(sb);
  		if (sb->s_root->d_inode)
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
804
  			coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
5fd31e9a6   Jan Harkes   coda: cleanup dow...
805
806
807
808
809
810
811
812
  		break;
  
  	case CODA_PURGEUSER:
  		coda_cache_clear_all(sb);
  		break;
  
  	case CODA_ZAPDIR:
  		fid = &out->coda_zapdir.CodaFid;
5fd31e9a6   Jan Harkes   coda: cleanup dow...
813
814
815
816
  		break;
  
  	case CODA_ZAPFILE:
  		fid = &out->coda_zapfile.CodaFid;
5fd31e9a6   Jan Harkes   coda: cleanup dow...
817
818
819
820
  		break;
  
  	case CODA_PURGEFID:
  		fid = &out->coda_purgefid.CodaFid;
5fd31e9a6   Jan Harkes   coda: cleanup dow...
821
822
823
824
  		break;
  
  	case CODA_REPLACE:
  		fid = &out->coda_replace.OldFid;
5fd31e9a6   Jan Harkes   coda: cleanup dow...
825
826
  		break;
  	}
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
827
828
  	if (fid)
  		inode = coda_fid_to_inode(fid, sb);
5fd31e9a6   Jan Harkes   coda: cleanup dow...
829

f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
830
  unlock_out:
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
  	mutex_unlock(&vcp->vc_mutex);
  
  	if (!inode)
  		return 0;
  
  	switch (opcode) {
  	case CODA_ZAPDIR:
  		coda_flag_inode_children(inode, C_PURGE);
  		coda_flag_inode(inode, C_VATTR);
  		break;
  
  	case CODA_ZAPFILE:
  		coda_flag_inode(inode, C_VATTR);
  		break;
  
  	case CODA_PURGEFID:
  		coda_flag_inode_children(inode, C_PURGE);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
848

da47c19e5   Yoshihisa Abe   Coda: replace BKL...
849
850
851
852
853
854
855
856
857
858
859
  		/* catch the dentries later if some are still busy */
  		coda_flag_inode(inode, C_PURGE);
  		d_prune_aliases(inode);
  		break;
  
  	case CODA_REPLACE:
  		newfid = &out->coda_replace.NewFid;
  		coda_replace_fid(inode, fid, newfid);
  		break;
  	}
  	iput(inode);
5fd31e9a6   Jan Harkes   coda: cleanup dow...
860
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
  }