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(¤t->sighand->siglock);
619*4882a593Smuzhiyun *old = current->blocked;
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun sigfillset(¤t->blocked);
622*4882a593Smuzhiyun sigdelset(¤t->blocked, SIGKILL);
623*4882a593Smuzhiyun sigdelset(¤t->blocked, SIGSTOP);
624*4882a593Smuzhiyun sigdelset(¤t->blocked, SIGINT);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun recalc_sigpending();
627*4882a593Smuzhiyun spin_unlock_irq(¤t->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(¤t->sighand->siglock);
633*4882a593Smuzhiyun current->blocked = *old;
634*4882a593Smuzhiyun recalc_sigpending();
635*4882a593Smuzhiyun spin_unlock_irq(¤t->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