xref: /OK3568_Linux_fs/kernel/fs/coda/upcall.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Mostly platform independent upcall operations to Venus:
4*4882a593Smuzhiyun  *  -- upcalls
5*4882a593Smuzhiyun  *  -- upcall routines
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Linux 2.0 version
8*4882a593Smuzhiyun  * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
9*4882a593Smuzhiyun  * Michael Callahan <callahan@maths.ox.ac.uk>
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * Redone for Linux 2.1
12*4882a593Smuzhiyun  * Copyright (C) 1997 Carnegie Mellon University
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * Carnegie Mellon University encourages users of this code to contribute
15*4882a593Smuzhiyun  * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/signal.h>
19*4882a593Smuzhiyun #include <linux/sched/signal.h>
20*4882a593Smuzhiyun #include <linux/types.h>
21*4882a593Smuzhiyun #include <linux/kernel.h>
22*4882a593Smuzhiyun #include <linux/mm.h>
23*4882a593Smuzhiyun #include <linux/time.h>
24*4882a593Smuzhiyun #include <linux/fs.h>
25*4882a593Smuzhiyun #include <linux/file.h>
26*4882a593Smuzhiyun #include <linux/stat.h>
27*4882a593Smuzhiyun #include <linux/errno.h>
28*4882a593Smuzhiyun #include <linux/string.h>
29*4882a593Smuzhiyun #include <linux/slab.h>
30*4882a593Smuzhiyun #include <linux/mutex.h>
31*4882a593Smuzhiyun #include <linux/uaccess.h>
32*4882a593Smuzhiyun #include <linux/vmalloc.h>
33*4882a593Smuzhiyun #include <linux/vfs.h>
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #include <linux/coda.h>
36*4882a593Smuzhiyun #include "coda_psdev.h"
37*4882a593Smuzhiyun #include "coda_linux.h"
38*4882a593Smuzhiyun #include "coda_cache.h"
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #include "coda_int.h"
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
43*4882a593Smuzhiyun 		       union inputArgs *buffer);
44*4882a593Smuzhiyun 
alloc_upcall(int opcode,int size)45*4882a593Smuzhiyun static void *alloc_upcall(int opcode, int size)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	union inputArgs *inp;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	inp = kvzalloc(size, GFP_KERNEL);
50*4882a593Smuzhiyun         if (!inp)
51*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun         inp->ih.opcode = opcode;
54*4882a593Smuzhiyun 	inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns);
55*4882a593Smuzhiyun 	inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
56*4882a593Smuzhiyun 	inp->ih.uid = from_kuid(&init_user_ns, current_fsuid());
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	return (void*)inp;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #define UPARG(op)\
62*4882a593Smuzhiyun do {\
63*4882a593Smuzhiyun 	inp = (union inputArgs *)alloc_upcall(op, insize); \
64*4882a593Smuzhiyun         if (IS_ERR(inp)) { return PTR_ERR(inp); }\
65*4882a593Smuzhiyun         outp = (union outputArgs *)(inp); \
66*4882a593Smuzhiyun         outsize = insize; \
67*4882a593Smuzhiyun } while (0)
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
70*4882a593Smuzhiyun #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
71*4882a593Smuzhiyun #define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun /* the upcalls */
venus_rootfid(struct super_block * sb,struct CodaFid * fidp)75*4882a593Smuzhiyun int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun         union inputArgs *inp;
78*4882a593Smuzhiyun         union outputArgs *outp;
79*4882a593Smuzhiyun         int insize, outsize, error;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun         insize = SIZE(root);
82*4882a593Smuzhiyun         UPARG(CODA_ROOT);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
85*4882a593Smuzhiyun 	if (!error)
86*4882a593Smuzhiyun 		*fidp = outp->coda_root.VFid;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	kvfree(inp);
89*4882a593Smuzhiyun 	return error;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
venus_getattr(struct super_block * sb,struct CodaFid * fid,struct coda_vattr * attr)92*4882a593Smuzhiyun int venus_getattr(struct super_block *sb, struct CodaFid *fid,
93*4882a593Smuzhiyun 		     struct coda_vattr *attr)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun         union inputArgs *inp;
96*4882a593Smuzhiyun         union outputArgs *outp;
97*4882a593Smuzhiyun         int insize, outsize, error;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun         insize = SIZE(getattr);
100*4882a593Smuzhiyun 	UPARG(CODA_GETATTR);
101*4882a593Smuzhiyun         inp->coda_getattr.VFid = *fid;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
104*4882a593Smuzhiyun 	if (!error)
105*4882a593Smuzhiyun 		*attr = outp->coda_getattr.attr;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	kvfree(inp);
108*4882a593Smuzhiyun         return error;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
venus_setattr(struct super_block * sb,struct CodaFid * fid,struct coda_vattr * vattr)111*4882a593Smuzhiyun int venus_setattr(struct super_block *sb, struct CodaFid *fid,
112*4882a593Smuzhiyun 		  struct coda_vattr *vattr)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun         union inputArgs *inp;
115*4882a593Smuzhiyun         union outputArgs *outp;
116*4882a593Smuzhiyun         int insize, outsize, error;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	insize = SIZE(setattr);
119*4882a593Smuzhiyun 	UPARG(CODA_SETATTR);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun         inp->coda_setattr.VFid = *fid;
122*4882a593Smuzhiyun 	inp->coda_setattr.attr = *vattr;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	kvfree(inp);
127*4882a593Smuzhiyun         return error;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
venus_lookup(struct super_block * sb,struct CodaFid * fid,const char * name,int length,int * type,struct CodaFid * resfid)130*4882a593Smuzhiyun int venus_lookup(struct super_block *sb, struct CodaFid *fid,
131*4882a593Smuzhiyun 		    const char *name, int length, int * type,
132*4882a593Smuzhiyun 		    struct CodaFid *resfid)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun         union inputArgs *inp;
135*4882a593Smuzhiyun         union outputArgs *outp;
136*4882a593Smuzhiyun         int insize, outsize, error;
137*4882a593Smuzhiyun 	int offset;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	offset = INSIZE(lookup);
140*4882a593Smuzhiyun         insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
141*4882a593Smuzhiyun 	UPARG(CODA_LOOKUP);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun         inp->coda_lookup.VFid = *fid;
144*4882a593Smuzhiyun 	inp->coda_lookup.name = offset;
145*4882a593Smuzhiyun 	inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
146*4882a593Smuzhiyun         /* send Venus a null terminated string */
147*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, name, length);
148*4882a593Smuzhiyun         *((char *)inp + offset + length) = '\0';
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
151*4882a593Smuzhiyun 	if (!error) {
152*4882a593Smuzhiyun 		*resfid = outp->coda_lookup.VFid;
153*4882a593Smuzhiyun 		*type = outp->coda_lookup.vtype;
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	kvfree(inp);
157*4882a593Smuzhiyun 	return error;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
venus_close(struct super_block * sb,struct CodaFid * fid,int flags,kuid_t uid)160*4882a593Smuzhiyun int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
161*4882a593Smuzhiyun 		kuid_t uid)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	union inputArgs *inp;
164*4882a593Smuzhiyun 	union outputArgs *outp;
165*4882a593Smuzhiyun 	int insize, outsize, error;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	insize = SIZE(release);
168*4882a593Smuzhiyun 	UPARG(CODA_CLOSE);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	inp->ih.uid = from_kuid(&init_user_ns, uid);
171*4882a593Smuzhiyun         inp->coda_close.VFid = *fid;
172*4882a593Smuzhiyun         inp->coda_close.flags = flags;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	kvfree(inp);
177*4882a593Smuzhiyun         return error;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
venus_open(struct super_block * sb,struct CodaFid * fid,int flags,struct file ** fh)180*4882a593Smuzhiyun int venus_open(struct super_block *sb, struct CodaFid *fid,
181*4882a593Smuzhiyun 		  int flags, struct file **fh)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun         union inputArgs *inp;
184*4882a593Smuzhiyun         union outputArgs *outp;
185*4882a593Smuzhiyun         int insize, outsize, error;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	insize = SIZE(open_by_fd);
188*4882a593Smuzhiyun 	UPARG(CODA_OPEN_BY_FD);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	inp->coda_open_by_fd.VFid = *fid;
191*4882a593Smuzhiyun 	inp->coda_open_by_fd.flags = flags;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
194*4882a593Smuzhiyun 	if (!error)
195*4882a593Smuzhiyun 		*fh = outp->coda_open_by_fd.fh;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	kvfree(inp);
198*4882a593Smuzhiyun 	return error;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
venus_mkdir(struct super_block * sb,struct CodaFid * dirfid,const char * name,int length,struct CodaFid * newfid,struct coda_vattr * attrs)201*4882a593Smuzhiyun int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
202*4882a593Smuzhiyun 		   const char *name, int length,
203*4882a593Smuzhiyun 		   struct CodaFid *newfid, struct coda_vattr *attrs)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun         union inputArgs *inp;
206*4882a593Smuzhiyun         union outputArgs *outp;
207*4882a593Smuzhiyun         int insize, outsize, error;
208*4882a593Smuzhiyun         int offset;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	offset = INSIZE(mkdir);
211*4882a593Smuzhiyun 	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
212*4882a593Smuzhiyun 	UPARG(CODA_MKDIR);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun         inp->coda_mkdir.VFid = *dirfid;
215*4882a593Smuzhiyun         inp->coda_mkdir.attr = *attrs;
216*4882a593Smuzhiyun 	inp->coda_mkdir.name = offset;
217*4882a593Smuzhiyun         /* Venus must get null terminated string */
218*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, name, length);
219*4882a593Smuzhiyun         *((char *)inp + offset + length) = '\0';
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
222*4882a593Smuzhiyun 	if (!error) {
223*4882a593Smuzhiyun 		*attrs = outp->coda_mkdir.attr;
224*4882a593Smuzhiyun 		*newfid = outp->coda_mkdir.VFid;
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	kvfree(inp);
228*4882a593Smuzhiyun 	return error;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 
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)232*4882a593Smuzhiyun int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
233*4882a593Smuzhiyun 		 struct CodaFid *new_fid, size_t old_length,
234*4882a593Smuzhiyun 		 size_t new_length, const char *old_name,
235*4882a593Smuzhiyun 		 const char *new_name)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	union inputArgs *inp;
238*4882a593Smuzhiyun         union outputArgs *outp;
239*4882a593Smuzhiyun         int insize, outsize, error;
240*4882a593Smuzhiyun 	int offset, s;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	offset = INSIZE(rename);
243*4882a593Smuzhiyun 	insize = max_t(unsigned int, offset + new_length + old_length + 8,
244*4882a593Smuzhiyun 		     OUTSIZE(rename));
245*4882a593Smuzhiyun  	UPARG(CODA_RENAME);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun         inp->coda_rename.sourceFid = *old_fid;
248*4882a593Smuzhiyun         inp->coda_rename.destFid =  *new_fid;
249*4882a593Smuzhiyun         inp->coda_rename.srcname = offset;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun         /* Venus must receive an null terminated string */
252*4882a593Smuzhiyun         s = ( old_length & ~0x3) +4; /* round up to word boundary */
253*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, old_name, old_length);
254*4882a593Smuzhiyun         *((char *)inp + offset + old_length) = '\0';
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun         /* another null terminated string for Venus */
257*4882a593Smuzhiyun         offset += s;
258*4882a593Smuzhiyun         inp->coda_rename.destname = offset;
259*4882a593Smuzhiyun         s = ( new_length & ~0x3) +4; /* round up to word boundary */
260*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, new_name, new_length);
261*4882a593Smuzhiyun         *((char *)inp + offset + new_length) = '\0';
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	kvfree(inp);
266*4882a593Smuzhiyun 	return error;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
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)269*4882a593Smuzhiyun int venus_create(struct super_block *sb, struct CodaFid *dirfid,
270*4882a593Smuzhiyun 		 const char *name, int length, int excl, int mode,
271*4882a593Smuzhiyun 		 struct CodaFid *newfid, struct coda_vattr *attrs)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun         union inputArgs *inp;
274*4882a593Smuzhiyun         union outputArgs *outp;
275*4882a593Smuzhiyun         int insize, outsize, error;
276*4882a593Smuzhiyun         int offset;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun         offset = INSIZE(create);
279*4882a593Smuzhiyun 	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
280*4882a593Smuzhiyun 	UPARG(CODA_CREATE);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun         inp->coda_create.VFid = *dirfid;
283*4882a593Smuzhiyun         inp->coda_create.attr.va_mode = mode;
284*4882a593Smuzhiyun 	inp->coda_create.excl = excl;
285*4882a593Smuzhiyun         inp->coda_create.mode = mode;
286*4882a593Smuzhiyun         inp->coda_create.name = offset;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun         /* Venus must get null terminated string */
289*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, name, length);
290*4882a593Smuzhiyun         *((char *)inp + offset + length) = '\0';
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
293*4882a593Smuzhiyun 	if (!error) {
294*4882a593Smuzhiyun 		*attrs = outp->coda_create.attr;
295*4882a593Smuzhiyun 		*newfid = outp->coda_create.VFid;
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	kvfree(inp);
299*4882a593Smuzhiyun 	return error;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
venus_rmdir(struct super_block * sb,struct CodaFid * dirfid,const char * name,int length)302*4882a593Smuzhiyun int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
303*4882a593Smuzhiyun 		    const char *name, int length)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun         union inputArgs *inp;
306*4882a593Smuzhiyun         union outputArgs *outp;
307*4882a593Smuzhiyun         int insize, outsize, error;
308*4882a593Smuzhiyun         int offset;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun         offset = INSIZE(rmdir);
311*4882a593Smuzhiyun 	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
312*4882a593Smuzhiyun 	UPARG(CODA_RMDIR);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun         inp->coda_rmdir.VFid = *dirfid;
315*4882a593Smuzhiyun         inp->coda_rmdir.name = offset;
316*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, name, length);
317*4882a593Smuzhiyun 	*((char *)inp + offset + length) = '\0';
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	kvfree(inp);
322*4882a593Smuzhiyun 	return error;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
venus_remove(struct super_block * sb,struct CodaFid * dirfid,const char * name,int length)325*4882a593Smuzhiyun int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
326*4882a593Smuzhiyun 		    const char *name, int length)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun         union inputArgs *inp;
329*4882a593Smuzhiyun         union outputArgs *outp;
330*4882a593Smuzhiyun         int error=0, insize, outsize, offset;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun         offset = INSIZE(remove);
333*4882a593Smuzhiyun 	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
334*4882a593Smuzhiyun 	UPARG(CODA_REMOVE);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun         inp->coda_remove.VFid = *dirfid;
337*4882a593Smuzhiyun         inp->coda_remove.name = offset;
338*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, name, length);
339*4882a593Smuzhiyun 	*((char *)inp + offset + length) = '\0';
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	kvfree(inp);
344*4882a593Smuzhiyun 	return error;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
venus_readlink(struct super_block * sb,struct CodaFid * fid,char * buffer,int * length)347*4882a593Smuzhiyun int venus_readlink(struct super_block *sb, struct CodaFid *fid,
348*4882a593Smuzhiyun 		      char *buffer, int *length)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun         union inputArgs *inp;
351*4882a593Smuzhiyun         union outputArgs *outp;
352*4882a593Smuzhiyun         int insize, outsize, error;
353*4882a593Smuzhiyun         int retlen;
354*4882a593Smuzhiyun         char *result;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	insize = max_t(unsigned int,
357*4882a593Smuzhiyun 		     INSIZE(readlink), OUTSIZE(readlink)+ *length);
358*4882a593Smuzhiyun 	UPARG(CODA_READLINK);
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun         inp->coda_readlink.VFid = *fid;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
363*4882a593Smuzhiyun 	if (!error) {
364*4882a593Smuzhiyun 		retlen = outp->coda_readlink.count;
365*4882a593Smuzhiyun 		if (retlen >= *length)
366*4882a593Smuzhiyun 			retlen = *length - 1;
367*4882a593Smuzhiyun 		*length = retlen;
368*4882a593Smuzhiyun 		result =  (char *)outp + (long)outp->coda_readlink.data;
369*4882a593Smuzhiyun 		memcpy(buffer, result, retlen);
370*4882a593Smuzhiyun 		*(buffer + retlen) = '\0';
371*4882a593Smuzhiyun 	}
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	kvfree(inp);
374*4882a593Smuzhiyun         return error;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 
venus_link(struct super_block * sb,struct CodaFid * fid,struct CodaFid * dirfid,const char * name,int len)379*4882a593Smuzhiyun int venus_link(struct super_block *sb, struct CodaFid *fid,
380*4882a593Smuzhiyun 		  struct CodaFid *dirfid, const char *name, int len )
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun         union inputArgs *inp;
383*4882a593Smuzhiyun         union outputArgs *outp;
384*4882a593Smuzhiyun         int insize, outsize, error;
385*4882a593Smuzhiyun         int offset;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	offset = INSIZE(link);
388*4882a593Smuzhiyun 	insize = max_t(unsigned int, offset  + len + 1, OUTSIZE(link));
389*4882a593Smuzhiyun         UPARG(CODA_LINK);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun         inp->coda_link.sourceFid = *fid;
392*4882a593Smuzhiyun         inp->coda_link.destFid = *dirfid;
393*4882a593Smuzhiyun         inp->coda_link.tname = offset;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun         /* make sure strings are null terminated */
396*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, name, len);
397*4882a593Smuzhiyun         *((char *)inp + offset + len) = '\0';
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	kvfree(inp);
402*4882a593Smuzhiyun         return error;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
venus_symlink(struct super_block * sb,struct CodaFid * fid,const char * name,int len,const char * symname,int symlen)405*4882a593Smuzhiyun int venus_symlink(struct super_block *sb, struct CodaFid *fid,
406*4882a593Smuzhiyun 		     const char *name, int len,
407*4882a593Smuzhiyun 		     const char *symname, int symlen)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun         union inputArgs *inp;
410*4882a593Smuzhiyun         union outputArgs *outp;
411*4882a593Smuzhiyun         int insize, outsize, error;
412*4882a593Smuzhiyun         int offset, s;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun         offset = INSIZE(symlink);
415*4882a593Smuzhiyun 	insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
416*4882a593Smuzhiyun 	UPARG(CODA_SYMLINK);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun         /*        inp->coda_symlink.attr = *tva; XXXXXX */
419*4882a593Smuzhiyun         inp->coda_symlink.VFid = *fid;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	/* Round up to word boundary and null terminate */
422*4882a593Smuzhiyun         inp->coda_symlink.srcname = offset;
423*4882a593Smuzhiyun         s = ( symlen  & ~0x3 ) + 4;
424*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, symname, symlen);
425*4882a593Smuzhiyun         *((char *)inp + offset + symlen) = '\0';
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	/* Round up to word boundary and null terminate */
428*4882a593Smuzhiyun         offset += s;
429*4882a593Smuzhiyun         inp->coda_symlink.tname = offset;
430*4882a593Smuzhiyun         s = (len & ~0x3) + 4;
431*4882a593Smuzhiyun         memcpy((char *)(inp) + offset, name, len);
432*4882a593Smuzhiyun         *((char *)inp + offset + len) = '\0';
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	kvfree(inp);
437*4882a593Smuzhiyun         return error;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
venus_fsync(struct super_block * sb,struct CodaFid * fid)440*4882a593Smuzhiyun int venus_fsync(struct super_block *sb, struct CodaFid *fid)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun         union inputArgs *inp;
443*4882a593Smuzhiyun         union outputArgs *outp;
444*4882a593Smuzhiyun 	int insize, outsize, error;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	insize=SIZE(fsync);
447*4882a593Smuzhiyun 	UPARG(CODA_FSYNC);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	inp->coda_fsync.VFid = *fid;
450*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	kvfree(inp);
453*4882a593Smuzhiyun 	return error;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun 
venus_access(struct super_block * sb,struct CodaFid * fid,int mask)456*4882a593Smuzhiyun int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun         union inputArgs *inp;
459*4882a593Smuzhiyun         union outputArgs *outp;
460*4882a593Smuzhiyun 	int insize, outsize, error;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	insize = SIZE(access);
463*4882a593Smuzhiyun 	UPARG(CODA_ACCESS);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun         inp->coda_access.VFid = *fid;
466*4882a593Smuzhiyun         inp->coda_access.flags = mask;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	kvfree(inp);
471*4882a593Smuzhiyun 	return error;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 
venus_pioctl(struct super_block * sb,struct CodaFid * fid,unsigned int cmd,struct PioctlData * data)475*4882a593Smuzhiyun int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
476*4882a593Smuzhiyun 		 unsigned int cmd, struct PioctlData *data)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun         union inputArgs *inp;
479*4882a593Smuzhiyun         union outputArgs *outp;
480*4882a593Smuzhiyun 	int insize, outsize, error;
481*4882a593Smuzhiyun 	int iocsize;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	insize = VC_MAXMSGSIZE;
484*4882a593Smuzhiyun 	UPARG(CODA_IOCTL);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun         /* build packet for Venus */
487*4882a593Smuzhiyun         if (data->vi.in_size > VC_MAXDATASIZE) {
488*4882a593Smuzhiyun 		error = -EINVAL;
489*4882a593Smuzhiyun 		goto exit;
490*4882a593Smuzhiyun         }
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun         if (data->vi.out_size > VC_MAXDATASIZE) {
493*4882a593Smuzhiyun 		error = -EINVAL;
494*4882a593Smuzhiyun 		goto exit;
495*4882a593Smuzhiyun 	}
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun         inp->coda_ioctl.VFid = *fid;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun         /* the cmd field was mutated by increasing its size field to
500*4882a593Smuzhiyun          * reflect the path and follow args. We need to subtract that
501*4882a593Smuzhiyun          * out before sending the command to Venus.  */
502*4882a593Smuzhiyun         inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
503*4882a593Smuzhiyun         iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
504*4882a593Smuzhiyun         inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<	16;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun         /* in->coda_ioctl.rwflag = flag; */
507*4882a593Smuzhiyun         inp->coda_ioctl.len = data->vi.in_size;
508*4882a593Smuzhiyun         inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun         /* get the data out of user space */
511*4882a593Smuzhiyun 	if (copy_from_user((char *)inp + (long)inp->coda_ioctl.data,
512*4882a593Smuzhiyun 			   data->vi.in, data->vi.in_size)) {
513*4882a593Smuzhiyun 		error = -EINVAL;
514*4882a593Smuzhiyun 	        goto exit;
515*4882a593Smuzhiyun 	}
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
518*4882a593Smuzhiyun 			    &outsize, inp);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun         if (error) {
521*4882a593Smuzhiyun 		pr_warn("%s: Venus returns: %d for %s\n",
522*4882a593Smuzhiyun 			__func__, error, coda_f2s(fid));
523*4882a593Smuzhiyun 		goto exit;
524*4882a593Smuzhiyun 	}
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
527*4882a593Smuzhiyun 		error = -EINVAL;
528*4882a593Smuzhiyun 		goto exit;
529*4882a593Smuzhiyun 	}
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	/* Copy out the OUT buffer. */
532*4882a593Smuzhiyun         if (outp->coda_ioctl.len > data->vi.out_size) {
533*4882a593Smuzhiyun 		error = -EINVAL;
534*4882a593Smuzhiyun 		goto exit;
535*4882a593Smuzhiyun         }
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	/* Copy out the OUT buffer. */
538*4882a593Smuzhiyun 	if (copy_to_user(data->vi.out,
539*4882a593Smuzhiyun 			 (char *)outp + (long)outp->coda_ioctl.data,
540*4882a593Smuzhiyun 			 outp->coda_ioctl.len)) {
541*4882a593Smuzhiyun 		error = -EFAULT;
542*4882a593Smuzhiyun 		goto exit;
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun  exit:
546*4882a593Smuzhiyun 	kvfree(inp);
547*4882a593Smuzhiyun 	return error;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
venus_statfs(struct dentry * dentry,struct kstatfs * sfs)550*4882a593Smuzhiyun int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun         union inputArgs *inp;
553*4882a593Smuzhiyun         union outputArgs *outp;
554*4882a593Smuzhiyun         int insize, outsize, error;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	insize = SIZE(statfs);
557*4882a593Smuzhiyun 	UPARG(CODA_STATFS);
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
560*4882a593Smuzhiyun 	if (!error) {
561*4882a593Smuzhiyun 		sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
562*4882a593Smuzhiyun 		sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
563*4882a593Smuzhiyun 		sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
564*4882a593Smuzhiyun 		sfs->f_files  = outp->coda_statfs.stat.f_files;
565*4882a593Smuzhiyun 		sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
566*4882a593Smuzhiyun 	}
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	kvfree(inp);
569*4882a593Smuzhiyun         return error;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun 
venus_access_intent(struct super_block * sb,struct CodaFid * fid,bool * access_intent_supported,size_t count,loff_t ppos,int type)572*4882a593Smuzhiyun int venus_access_intent(struct super_block *sb, struct CodaFid *fid,
573*4882a593Smuzhiyun 			bool *access_intent_supported,
574*4882a593Smuzhiyun 			size_t count, loff_t ppos, int type)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun 	union inputArgs *inp;
577*4882a593Smuzhiyun 	union outputArgs *outp;
578*4882a593Smuzhiyun 	int insize, outsize, error;
579*4882a593Smuzhiyun 	bool finalizer =
580*4882a593Smuzhiyun 		type == CODA_ACCESS_TYPE_READ_FINISH ||
581*4882a593Smuzhiyun 		type == CODA_ACCESS_TYPE_WRITE_FINISH;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	if (!*access_intent_supported && !finalizer)
584*4882a593Smuzhiyun 		return 0;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	insize = SIZE(access_intent);
587*4882a593Smuzhiyun 	UPARG(CODA_ACCESS_INTENT);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	inp->coda_access_intent.VFid = *fid;
590*4882a593Smuzhiyun 	inp->coda_access_intent.count = count;
591*4882a593Smuzhiyun 	inp->coda_access_intent.pos = ppos;
592*4882a593Smuzhiyun 	inp->coda_access_intent.type = type;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	error = coda_upcall(coda_vcp(sb), insize,
595*4882a593Smuzhiyun 			    finalizer ? NULL : &outsize, inp);
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	/*
598*4882a593Smuzhiyun 	 * we have to free the request buffer for synchronous upcalls
599*4882a593Smuzhiyun 	 * or when asynchronous upcalls fail, but not when asynchronous
600*4882a593Smuzhiyun 	 * upcalls succeed
601*4882a593Smuzhiyun 	 */
602*4882a593Smuzhiyun 	if (!finalizer || error)
603*4882a593Smuzhiyun 		kvfree(inp);
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	/* Chunked access is not supported or an old Coda client */
606*4882a593Smuzhiyun 	if (error == -EOPNOTSUPP) {
607*4882a593Smuzhiyun 		*access_intent_supported = false;
608*4882a593Smuzhiyun 		error = 0;
609*4882a593Smuzhiyun 	}
610*4882a593Smuzhiyun 	return error;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun /*
614*4882a593Smuzhiyun  * coda_upcall and coda_downcall routines.
615*4882a593Smuzhiyun  */
coda_block_signals(sigset_t * old)616*4882a593Smuzhiyun static void coda_block_signals(sigset_t *old)
617*4882a593Smuzhiyun {
618*4882a593Smuzhiyun 	spin_lock_irq(&current->sighand->siglock);
619*4882a593Smuzhiyun 	*old = current->blocked;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	sigfillset(&current->blocked);
622*4882a593Smuzhiyun 	sigdelset(&current->blocked, SIGKILL);
623*4882a593Smuzhiyun 	sigdelset(&current->blocked, SIGSTOP);
624*4882a593Smuzhiyun 	sigdelset(&current->blocked, SIGINT);
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	recalc_sigpending();
627*4882a593Smuzhiyun 	spin_unlock_irq(&current->sighand->siglock);
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
coda_unblock_signals(sigset_t * old)630*4882a593Smuzhiyun static void coda_unblock_signals(sigset_t *old)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun 	spin_lock_irq(&current->sighand->siglock);
633*4882a593Smuzhiyun 	current->blocked = *old;
634*4882a593Smuzhiyun 	recalc_sigpending();
635*4882a593Smuzhiyun 	spin_unlock_irq(&current->sighand->siglock);
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun /* Don't allow signals to interrupt the following upcalls before venus
639*4882a593Smuzhiyun  * has seen them,
640*4882a593Smuzhiyun  * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
641*4882a593Smuzhiyun  * - CODA_STORE				(to avoid data loss)
642*4882a593Smuzhiyun  * - CODA_ACCESS_INTENT                 (to avoid reference count problems)
643*4882a593Smuzhiyun  */
644*4882a593Smuzhiyun #define CODA_INTERRUPTIBLE(r) (!coda_hard && \
645*4882a593Smuzhiyun 			       (((r)->uc_opcode != CODA_CLOSE && \
646*4882a593Smuzhiyun 				 (r)->uc_opcode != CODA_STORE && \
647*4882a593Smuzhiyun 				 (r)->uc_opcode != CODA_ACCESS_INTENT && \
648*4882a593Smuzhiyun 				 (r)->uc_opcode != CODA_RELEASE) || \
649*4882a593Smuzhiyun 				(r)->uc_flags & CODA_REQ_READ))
650*4882a593Smuzhiyun 
coda_waitfor_upcall(struct venus_comm * vcp,struct upc_req * req)651*4882a593Smuzhiyun static inline void coda_waitfor_upcall(struct venus_comm *vcp,
652*4882a593Smuzhiyun 				       struct upc_req *req)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun 	DECLARE_WAITQUEUE(wait, current);
655*4882a593Smuzhiyun 	unsigned long timeout = jiffies + coda_timeout * HZ;
656*4882a593Smuzhiyun 	sigset_t old;
657*4882a593Smuzhiyun 	int blocked;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	coda_block_signals(&old);
660*4882a593Smuzhiyun 	blocked = 1;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	add_wait_queue(&req->uc_sleep, &wait);
663*4882a593Smuzhiyun 	for (;;) {
664*4882a593Smuzhiyun 		if (CODA_INTERRUPTIBLE(req))
665*4882a593Smuzhiyun 			set_current_state(TASK_INTERRUPTIBLE);
666*4882a593Smuzhiyun 		else
667*4882a593Smuzhiyun 			set_current_state(TASK_UNINTERRUPTIBLE);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 		/* got a reply */
670*4882a593Smuzhiyun 		if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
671*4882a593Smuzhiyun 			break;
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 		if (blocked && time_after(jiffies, timeout) &&
674*4882a593Smuzhiyun 		    CODA_INTERRUPTIBLE(req))
675*4882a593Smuzhiyun 		{
676*4882a593Smuzhiyun 			coda_unblock_signals(&old);
677*4882a593Smuzhiyun 			blocked = 0;
678*4882a593Smuzhiyun 		}
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 		if (signal_pending(current)) {
681*4882a593Smuzhiyun 			list_del(&req->uc_chain);
682*4882a593Smuzhiyun 			break;
683*4882a593Smuzhiyun 		}
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 		mutex_unlock(&vcp->vc_mutex);
686*4882a593Smuzhiyun 		if (blocked)
687*4882a593Smuzhiyun 			schedule_timeout(HZ);
688*4882a593Smuzhiyun 		else
689*4882a593Smuzhiyun 			schedule();
690*4882a593Smuzhiyun 		mutex_lock(&vcp->vc_mutex);
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 	if (blocked)
693*4882a593Smuzhiyun 		coda_unblock_signals(&old);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	remove_wait_queue(&req->uc_sleep, &wait);
696*4882a593Smuzhiyun 	set_current_state(TASK_RUNNING);
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun /*
701*4882a593Smuzhiyun  * coda_upcall will return an error in the case of
702*4882a593Smuzhiyun  * failed communication with Venus _or_ will peek at Venus
703*4882a593Smuzhiyun  * reply and return Venus' error.
704*4882a593Smuzhiyun  *
705*4882a593Smuzhiyun  * As venus has 2 types of errors, normal errors (positive) and internal
706*4882a593Smuzhiyun  * errors (negative), normal errors are negated, while internal errors
707*4882a593Smuzhiyun  * are all mapped to -EINTR, while showing a nice warning message. (jh)
708*4882a593Smuzhiyun  */
coda_upcall(struct venus_comm * vcp,int inSize,int * outSize,union inputArgs * buffer)709*4882a593Smuzhiyun static int coda_upcall(struct venus_comm *vcp,
710*4882a593Smuzhiyun 		       int inSize, int *outSize,
711*4882a593Smuzhiyun 		       union inputArgs *buffer)
712*4882a593Smuzhiyun {
713*4882a593Smuzhiyun 	union outputArgs *out;
714*4882a593Smuzhiyun 	union inputArgs *sig_inputArgs;
715*4882a593Smuzhiyun 	struct upc_req *req = NULL, *sig_req;
716*4882a593Smuzhiyun 	int error;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	mutex_lock(&vcp->vc_mutex);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	if (!vcp->vc_inuse) {
721*4882a593Smuzhiyun 		pr_notice("Venus dead, not sending upcall\n");
722*4882a593Smuzhiyun 		error = -ENXIO;
723*4882a593Smuzhiyun 		goto exit;
724*4882a593Smuzhiyun 	}
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	/* Format the request message. */
727*4882a593Smuzhiyun 	req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
728*4882a593Smuzhiyun 	if (!req) {
729*4882a593Smuzhiyun 		error = -ENOMEM;
730*4882a593Smuzhiyun 		goto exit;
731*4882a593Smuzhiyun 	}
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	buffer->ih.unique = ++vcp->vc_seq;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	req->uc_data = (void *)buffer;
736*4882a593Smuzhiyun 	req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
737*4882a593Smuzhiyun 	req->uc_inSize = inSize;
738*4882a593Smuzhiyun 	req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
739*4882a593Smuzhiyun 	req->uc_opcode = buffer->ih.opcode;
740*4882a593Smuzhiyun 	req->uc_unique = buffer->ih.unique;
741*4882a593Smuzhiyun 	init_waitqueue_head(&req->uc_sleep);
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	/* Append msg to pending queue and poke Venus. */
744*4882a593Smuzhiyun 	list_add_tail(&req->uc_chain, &vcp->vc_pending);
745*4882a593Smuzhiyun 	wake_up_interruptible(&vcp->vc_waitq);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	if (req->uc_flags & CODA_REQ_ASYNC) {
748*4882a593Smuzhiyun 		mutex_unlock(&vcp->vc_mutex);
749*4882a593Smuzhiyun 		return 0;
750*4882a593Smuzhiyun 	}
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	/* We can be interrupted while we wait for Venus to process
753*4882a593Smuzhiyun 	 * our request.  If the interrupt occurs before Venus has read
754*4882a593Smuzhiyun 	 * the request, we dequeue and return. If it occurs after the
755*4882a593Smuzhiyun 	 * read but before the reply, we dequeue, send a signal
756*4882a593Smuzhiyun 	 * message, and return. If it occurs after the reply we ignore
757*4882a593Smuzhiyun 	 * it. In no case do we want to restart the syscall.  If it
758*4882a593Smuzhiyun 	 * was interrupted by a venus shutdown (psdev_close), return
759*4882a593Smuzhiyun 	 * ENODEV.  */
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	/* Go to sleep.  Wake up on signals only after the timeout. */
762*4882a593Smuzhiyun 	coda_waitfor_upcall(vcp, req);
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	/* Op went through, interrupt or not... */
765*4882a593Smuzhiyun 	if (req->uc_flags & CODA_REQ_WRITE) {
766*4882a593Smuzhiyun 		out = (union outputArgs *)req->uc_data;
767*4882a593Smuzhiyun 		/* here we map positive Venus errors to kernel errors */
768*4882a593Smuzhiyun 		error = -out->oh.result;
769*4882a593Smuzhiyun 		*outSize = req->uc_outSize;
770*4882a593Smuzhiyun 		goto exit;
771*4882a593Smuzhiyun 	}
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	error = -EINTR;
774*4882a593Smuzhiyun 	if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
775*4882a593Smuzhiyun 		pr_warn("Unexpected interruption.\n");
776*4882a593Smuzhiyun 		goto exit;
777*4882a593Smuzhiyun 	}
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	/* Interrupted before venus read it. */
780*4882a593Smuzhiyun 	if (!(req->uc_flags & CODA_REQ_READ))
781*4882a593Smuzhiyun 		goto exit;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	/* Venus saw the upcall, make sure we can send interrupt signal */
784*4882a593Smuzhiyun 	if (!vcp->vc_inuse) {
785*4882a593Smuzhiyun 		pr_info("Venus dead, not sending signal.\n");
786*4882a593Smuzhiyun 		goto exit;
787*4882a593Smuzhiyun 	}
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	error = -ENOMEM;
790*4882a593Smuzhiyun 	sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
791*4882a593Smuzhiyun 	if (!sig_req) goto exit;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	sig_inputArgs = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL);
794*4882a593Smuzhiyun 	if (!sig_inputArgs) {
795*4882a593Smuzhiyun 		kfree(sig_req);
796*4882a593Smuzhiyun 		goto exit;
797*4882a593Smuzhiyun 	}
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	error = -EINTR;
800*4882a593Smuzhiyun 	sig_inputArgs->ih.opcode = CODA_SIGNAL;
801*4882a593Smuzhiyun 	sig_inputArgs->ih.unique = req->uc_unique;
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	sig_req->uc_flags = CODA_REQ_ASYNC;
804*4882a593Smuzhiyun 	sig_req->uc_opcode = sig_inputArgs->ih.opcode;
805*4882a593Smuzhiyun 	sig_req->uc_unique = sig_inputArgs->ih.unique;
806*4882a593Smuzhiyun 	sig_req->uc_data = (void *)sig_inputArgs;
807*4882a593Smuzhiyun 	sig_req->uc_inSize = sizeof(struct coda_in_hdr);
808*4882a593Smuzhiyun 	sig_req->uc_outSize = sizeof(struct coda_in_hdr);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	/* insert at head of queue! */
811*4882a593Smuzhiyun 	list_add(&(sig_req->uc_chain), &vcp->vc_pending);
812*4882a593Smuzhiyun 	wake_up_interruptible(&vcp->vc_waitq);
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun exit:
815*4882a593Smuzhiyun 	kfree(req);
816*4882a593Smuzhiyun 	mutex_unlock(&vcp->vc_mutex);
817*4882a593Smuzhiyun 	return error;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun /*
821*4882a593Smuzhiyun     The statements below are part of the Coda opportunistic
822*4882a593Smuzhiyun     programming -- taken from the Mach/BSD kernel code for Coda.
823*4882a593Smuzhiyun     You don't get correct semantics by stating what needs to be
824*4882a593Smuzhiyun     done without guaranteeing the invariants needed for it to happen.
825*4882a593Smuzhiyun     When will be have time to find out what exactly is going on?  (pjb)
826*4882a593Smuzhiyun */
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun /*
830*4882a593Smuzhiyun  * There are 7 cases where cache invalidations occur.  The semantics
831*4882a593Smuzhiyun  *  of each is listed here:
832*4882a593Smuzhiyun  *
833*4882a593Smuzhiyun  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
834*4882a593Smuzhiyun  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
835*4882a593Smuzhiyun  *                  This call is a result of token expiration.
836*4882a593Smuzhiyun  *
837*4882a593Smuzhiyun  * The next arise as the result of callbacks on a file or directory.
838*4882a593Smuzhiyun  * CODA_ZAPFILE   -- flush the cached attributes for a file.
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun  * CODA_ZAPDIR    -- flush the attributes for the dir and
841*4882a593Smuzhiyun  *                  force a new lookup for all the children
842*4882a593Smuzhiyun                     of this dir.
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun  *
845*4882a593Smuzhiyun  * The next is a result of Venus detecting an inconsistent file.
846*4882a593Smuzhiyun  * CODA_PURGEFID  -- flush the attribute for the file
847*4882a593Smuzhiyun  *                  purge it and its children from the dcache
848*4882a593Smuzhiyun  *
849*4882a593Smuzhiyun  * The last  allows Venus to replace local fids with global ones
850*4882a593Smuzhiyun  * during reintegration.
851*4882a593Smuzhiyun  *
852*4882a593Smuzhiyun  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
853*4882a593Smuzhiyun 
coda_downcall(struct venus_comm * vcp,int opcode,union outputArgs * out,size_t nbytes)854*4882a593Smuzhiyun int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
855*4882a593Smuzhiyun 		  size_t nbytes)
856*4882a593Smuzhiyun {
857*4882a593Smuzhiyun 	struct inode *inode = NULL;
858*4882a593Smuzhiyun 	struct CodaFid *fid = NULL, *newfid;
859*4882a593Smuzhiyun 	struct super_block *sb;
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	/*
862*4882a593Smuzhiyun 	 * Make sure we have received enough data from the cache
863*4882a593Smuzhiyun 	 * manager to populate the necessary fields in the buffer
864*4882a593Smuzhiyun 	 */
865*4882a593Smuzhiyun 	switch (opcode) {
866*4882a593Smuzhiyun 	case CODA_PURGEUSER:
867*4882a593Smuzhiyun 		if (nbytes < sizeof(struct coda_purgeuser_out))
868*4882a593Smuzhiyun 			return -EINVAL;
869*4882a593Smuzhiyun 		break;
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	case CODA_ZAPDIR:
872*4882a593Smuzhiyun 		if (nbytes < sizeof(struct coda_zapdir_out))
873*4882a593Smuzhiyun 			return -EINVAL;
874*4882a593Smuzhiyun 		break;
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	case CODA_ZAPFILE:
877*4882a593Smuzhiyun 		if (nbytes < sizeof(struct coda_zapfile_out))
878*4882a593Smuzhiyun 			return -EINVAL;
879*4882a593Smuzhiyun 		break;
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	case CODA_PURGEFID:
882*4882a593Smuzhiyun 		if (nbytes < sizeof(struct coda_purgefid_out))
883*4882a593Smuzhiyun 			return -EINVAL;
884*4882a593Smuzhiyun 		break;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	case CODA_REPLACE:
887*4882a593Smuzhiyun 		if (nbytes < sizeof(struct coda_replace_out))
888*4882a593Smuzhiyun 			return -EINVAL;
889*4882a593Smuzhiyun 		break;
890*4882a593Smuzhiyun 	}
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	/* Handle invalidation requests. */
893*4882a593Smuzhiyun 	mutex_lock(&vcp->vc_mutex);
894*4882a593Smuzhiyun 	sb = vcp->vc_sb;
895*4882a593Smuzhiyun 	if (!sb || !sb->s_root)
896*4882a593Smuzhiyun 		goto unlock_out;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	switch (opcode) {
899*4882a593Smuzhiyun 	case CODA_FLUSH:
900*4882a593Smuzhiyun 		coda_cache_clear_all(sb);
901*4882a593Smuzhiyun 		shrink_dcache_sb(sb);
902*4882a593Smuzhiyun 		if (d_really_is_positive(sb->s_root))
903*4882a593Smuzhiyun 			coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
904*4882a593Smuzhiyun 		break;
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	case CODA_PURGEUSER:
907*4882a593Smuzhiyun 		coda_cache_clear_all(sb);
908*4882a593Smuzhiyun 		break;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	case CODA_ZAPDIR:
911*4882a593Smuzhiyun 		fid = &out->coda_zapdir.CodaFid;
912*4882a593Smuzhiyun 		break;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	case CODA_ZAPFILE:
915*4882a593Smuzhiyun 		fid = &out->coda_zapfile.CodaFid;
916*4882a593Smuzhiyun 		break;
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun 	case CODA_PURGEFID:
919*4882a593Smuzhiyun 		fid = &out->coda_purgefid.CodaFid;
920*4882a593Smuzhiyun 		break;
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	case CODA_REPLACE:
923*4882a593Smuzhiyun 		fid = &out->coda_replace.OldFid;
924*4882a593Smuzhiyun 		break;
925*4882a593Smuzhiyun 	}
926*4882a593Smuzhiyun 	if (fid)
927*4882a593Smuzhiyun 		inode = coda_fid_to_inode(fid, sb);
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun unlock_out:
930*4882a593Smuzhiyun 	mutex_unlock(&vcp->vc_mutex);
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	if (!inode)
933*4882a593Smuzhiyun 		return 0;
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	switch (opcode) {
936*4882a593Smuzhiyun 	case CODA_ZAPDIR:
937*4882a593Smuzhiyun 		coda_flag_inode_children(inode, C_PURGE);
938*4882a593Smuzhiyun 		coda_flag_inode(inode, C_VATTR);
939*4882a593Smuzhiyun 		break;
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	case CODA_ZAPFILE:
942*4882a593Smuzhiyun 		coda_flag_inode(inode, C_VATTR);
943*4882a593Smuzhiyun 		break;
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	case CODA_PURGEFID:
946*4882a593Smuzhiyun 		coda_flag_inode_children(inode, C_PURGE);
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 		/* catch the dentries later if some are still busy */
949*4882a593Smuzhiyun 		coda_flag_inode(inode, C_PURGE);
950*4882a593Smuzhiyun 		d_prune_aliases(inode);
951*4882a593Smuzhiyun 		break;
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	case CODA_REPLACE:
954*4882a593Smuzhiyun 		newfid = &out->coda_replace.NewFid;
955*4882a593Smuzhiyun 		coda_replace_fid(inode, fid, newfid);
956*4882a593Smuzhiyun 		break;
957*4882a593Smuzhiyun 	}
958*4882a593Smuzhiyun 	iput(inode);
959*4882a593Smuzhiyun 	return 0;
960*4882a593Smuzhiyun }
961