xref: /kernel/linux/linux-5.10/fs/coda/upcall.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Mostly platform independent upcall operations to Venus:
48c2ecf20Sopenharmony_ci *  -- upcalls
58c2ecf20Sopenharmony_ci *  -- upcall routines
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Linux 2.0 version
88c2ecf20Sopenharmony_ci * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
98c2ecf20Sopenharmony_ci * Michael Callahan <callahan@maths.ox.ac.uk>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Redone for Linux 2.1
128c2ecf20Sopenharmony_ci * Copyright (C) 1997 Carnegie Mellon University
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Carnegie Mellon University encourages users of this code to contribute
158c2ecf20Sopenharmony_ci * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/signal.h>
198c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
208c2ecf20Sopenharmony_ci#include <linux/types.h>
218c2ecf20Sopenharmony_ci#include <linux/kernel.h>
228c2ecf20Sopenharmony_ci#include <linux/mm.h>
238c2ecf20Sopenharmony_ci#include <linux/time.h>
248c2ecf20Sopenharmony_ci#include <linux/fs.h>
258c2ecf20Sopenharmony_ci#include <linux/file.h>
268c2ecf20Sopenharmony_ci#include <linux/stat.h>
278c2ecf20Sopenharmony_ci#include <linux/errno.h>
288c2ecf20Sopenharmony_ci#include <linux/string.h>
298c2ecf20Sopenharmony_ci#include <linux/slab.h>
308c2ecf20Sopenharmony_ci#include <linux/mutex.h>
318c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
328c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
338c2ecf20Sopenharmony_ci#include <linux/vfs.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/coda.h>
368c2ecf20Sopenharmony_ci#include "coda_psdev.h"
378c2ecf20Sopenharmony_ci#include "coda_linux.h"
388c2ecf20Sopenharmony_ci#include "coda_cache.h"
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include "coda_int.h"
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
438c2ecf20Sopenharmony_ci		       union inputArgs *buffer);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic void *alloc_upcall(int opcode, int size)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	union inputArgs *inp;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	inp = kvzalloc(size, GFP_KERNEL);
508c2ecf20Sopenharmony_ci        if (!inp)
518c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci        inp->ih.opcode = opcode;
548c2ecf20Sopenharmony_ci	inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns);
558c2ecf20Sopenharmony_ci	inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns);
568c2ecf20Sopenharmony_ci	inp->ih.uid = from_kuid(&init_user_ns, current_fsuid());
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return (void*)inp;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define UPARG(op)\
628c2ecf20Sopenharmony_cido {\
638c2ecf20Sopenharmony_ci	inp = (union inputArgs *)alloc_upcall(op, insize); \
648c2ecf20Sopenharmony_ci        if (IS_ERR(inp)) { return PTR_ERR(inp); }\
658c2ecf20Sopenharmony_ci        outp = (union outputArgs *)(inp); \
668c2ecf20Sopenharmony_ci        outsize = insize; \
678c2ecf20Sopenharmony_ci} while (0)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
708c2ecf20Sopenharmony_ci#define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
718c2ecf20Sopenharmony_ci#define SIZE(tag)  max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/* the upcalls */
758c2ecf20Sopenharmony_ciint venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci        union inputArgs *inp;
788c2ecf20Sopenharmony_ci        union outputArgs *outp;
798c2ecf20Sopenharmony_ci        int insize, outsize, error;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci        insize = SIZE(root);
828c2ecf20Sopenharmony_ci        UPARG(CODA_ROOT);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
858c2ecf20Sopenharmony_ci	if (!error)
868c2ecf20Sopenharmony_ci		*fidp = outp->coda_root.VFid;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	kvfree(inp);
898c2ecf20Sopenharmony_ci	return error;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciint venus_getattr(struct super_block *sb, struct CodaFid *fid,
938c2ecf20Sopenharmony_ci		     struct coda_vattr *attr)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci        union inputArgs *inp;
968c2ecf20Sopenharmony_ci        union outputArgs *outp;
978c2ecf20Sopenharmony_ci        int insize, outsize, error;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci        insize = SIZE(getattr);
1008c2ecf20Sopenharmony_ci	UPARG(CODA_GETATTR);
1018c2ecf20Sopenharmony_ci        inp->coda_getattr.VFid = *fid;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1048c2ecf20Sopenharmony_ci	if (!error)
1058c2ecf20Sopenharmony_ci		*attr = outp->coda_getattr.attr;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	kvfree(inp);
1088c2ecf20Sopenharmony_ci        return error;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ciint venus_setattr(struct super_block *sb, struct CodaFid *fid,
1128c2ecf20Sopenharmony_ci		  struct coda_vattr *vattr)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci        union inputArgs *inp;
1158c2ecf20Sopenharmony_ci        union outputArgs *outp;
1168c2ecf20Sopenharmony_ci        int insize, outsize, error;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	insize = SIZE(setattr);
1198c2ecf20Sopenharmony_ci	UPARG(CODA_SETATTR);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci        inp->coda_setattr.VFid = *fid;
1228c2ecf20Sopenharmony_ci	inp->coda_setattr.attr = *vattr;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	kvfree(inp);
1278c2ecf20Sopenharmony_ci        return error;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciint venus_lookup(struct super_block *sb, struct CodaFid *fid,
1318c2ecf20Sopenharmony_ci		    const char *name, int length, int * type,
1328c2ecf20Sopenharmony_ci		    struct CodaFid *resfid)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci        union inputArgs *inp;
1358c2ecf20Sopenharmony_ci        union outputArgs *outp;
1368c2ecf20Sopenharmony_ci        int insize, outsize, error;
1378c2ecf20Sopenharmony_ci	int offset;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	offset = INSIZE(lookup);
1408c2ecf20Sopenharmony_ci        insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
1418c2ecf20Sopenharmony_ci	UPARG(CODA_LOOKUP);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci        inp->coda_lookup.VFid = *fid;
1448c2ecf20Sopenharmony_ci	inp->coda_lookup.name = offset;
1458c2ecf20Sopenharmony_ci	inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
1468c2ecf20Sopenharmony_ci        /* send Venus a null terminated string */
1478c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, name, length);
1488c2ecf20Sopenharmony_ci        *((char *)inp + offset + length) = '\0';
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1518c2ecf20Sopenharmony_ci	if (!error) {
1528c2ecf20Sopenharmony_ci		*resfid = outp->coda_lookup.VFid;
1538c2ecf20Sopenharmony_ci		*type = outp->coda_lookup.vtype;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	kvfree(inp);
1578c2ecf20Sopenharmony_ci	return error;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ciint venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
1618c2ecf20Sopenharmony_ci		kuid_t uid)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	union inputArgs *inp;
1648c2ecf20Sopenharmony_ci	union outputArgs *outp;
1658c2ecf20Sopenharmony_ci	int insize, outsize, error;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	insize = SIZE(release);
1688c2ecf20Sopenharmony_ci	UPARG(CODA_CLOSE);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	inp->ih.uid = from_kuid(&init_user_ns, uid);
1718c2ecf20Sopenharmony_ci        inp->coda_close.VFid = *fid;
1728c2ecf20Sopenharmony_ci        inp->coda_close.flags = flags;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	kvfree(inp);
1778c2ecf20Sopenharmony_ci        return error;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ciint venus_open(struct super_block *sb, struct CodaFid *fid,
1818c2ecf20Sopenharmony_ci		  int flags, struct file **fh)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci        union inputArgs *inp;
1848c2ecf20Sopenharmony_ci        union outputArgs *outp;
1858c2ecf20Sopenharmony_ci        int insize, outsize, error;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	insize = SIZE(open_by_fd);
1888c2ecf20Sopenharmony_ci	UPARG(CODA_OPEN_BY_FD);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	inp->coda_open_by_fd.VFid = *fid;
1918c2ecf20Sopenharmony_ci	inp->coda_open_by_fd.flags = flags;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
1948c2ecf20Sopenharmony_ci	if (!error)
1958c2ecf20Sopenharmony_ci		*fh = outp->coda_open_by_fd.fh;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	kvfree(inp);
1988c2ecf20Sopenharmony_ci	return error;
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ciint venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
2028c2ecf20Sopenharmony_ci		   const char *name, int length,
2038c2ecf20Sopenharmony_ci		   struct CodaFid *newfid, struct coda_vattr *attrs)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci        union inputArgs *inp;
2068c2ecf20Sopenharmony_ci        union outputArgs *outp;
2078c2ecf20Sopenharmony_ci        int insize, outsize, error;
2088c2ecf20Sopenharmony_ci        int offset;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	offset = INSIZE(mkdir);
2118c2ecf20Sopenharmony_ci	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
2128c2ecf20Sopenharmony_ci	UPARG(CODA_MKDIR);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci        inp->coda_mkdir.VFid = *dirfid;
2158c2ecf20Sopenharmony_ci        inp->coda_mkdir.attr = *attrs;
2168c2ecf20Sopenharmony_ci	inp->coda_mkdir.name = offset;
2178c2ecf20Sopenharmony_ci        /* Venus must get null terminated string */
2188c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, name, length);
2198c2ecf20Sopenharmony_ci        *((char *)inp + offset + length) = '\0';
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
2228c2ecf20Sopenharmony_ci	if (!error) {
2238c2ecf20Sopenharmony_ci		*attrs = outp->coda_mkdir.attr;
2248c2ecf20Sopenharmony_ci		*newfid = outp->coda_mkdir.VFid;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	kvfree(inp);
2288c2ecf20Sopenharmony_ci	return error;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ciint venus_rename(struct super_block *sb, struct CodaFid *old_fid,
2338c2ecf20Sopenharmony_ci		 struct CodaFid *new_fid, size_t old_length,
2348c2ecf20Sopenharmony_ci		 size_t new_length, const char *old_name,
2358c2ecf20Sopenharmony_ci		 const char *new_name)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	union inputArgs *inp;
2388c2ecf20Sopenharmony_ci        union outputArgs *outp;
2398c2ecf20Sopenharmony_ci        int insize, outsize, error;
2408c2ecf20Sopenharmony_ci	int offset, s;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	offset = INSIZE(rename);
2438c2ecf20Sopenharmony_ci	insize = max_t(unsigned int, offset + new_length + old_length + 8,
2448c2ecf20Sopenharmony_ci		     OUTSIZE(rename));
2458c2ecf20Sopenharmony_ci 	UPARG(CODA_RENAME);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci        inp->coda_rename.sourceFid = *old_fid;
2488c2ecf20Sopenharmony_ci        inp->coda_rename.destFid =  *new_fid;
2498c2ecf20Sopenharmony_ci        inp->coda_rename.srcname = offset;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci        /* Venus must receive an null terminated string */
2528c2ecf20Sopenharmony_ci        s = ( old_length & ~0x3) +4; /* round up to word boundary */
2538c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, old_name, old_length);
2548c2ecf20Sopenharmony_ci        *((char *)inp + offset + old_length) = '\0';
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci        /* another null terminated string for Venus */
2578c2ecf20Sopenharmony_ci        offset += s;
2588c2ecf20Sopenharmony_ci        inp->coda_rename.destname = offset;
2598c2ecf20Sopenharmony_ci        s = ( new_length & ~0x3) +4; /* round up to word boundary */
2608c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, new_name, new_length);
2618c2ecf20Sopenharmony_ci        *((char *)inp + offset + new_length) = '\0';
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	kvfree(inp);
2668c2ecf20Sopenharmony_ci	return error;
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ciint venus_create(struct super_block *sb, struct CodaFid *dirfid,
2708c2ecf20Sopenharmony_ci		 const char *name, int length, int excl, int mode,
2718c2ecf20Sopenharmony_ci		 struct CodaFid *newfid, struct coda_vattr *attrs)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci        union inputArgs *inp;
2748c2ecf20Sopenharmony_ci        union outputArgs *outp;
2758c2ecf20Sopenharmony_ci        int insize, outsize, error;
2768c2ecf20Sopenharmony_ci        int offset;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci        offset = INSIZE(create);
2798c2ecf20Sopenharmony_ci	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
2808c2ecf20Sopenharmony_ci	UPARG(CODA_CREATE);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci        inp->coda_create.VFid = *dirfid;
2838c2ecf20Sopenharmony_ci        inp->coda_create.attr.va_mode = mode;
2848c2ecf20Sopenharmony_ci	inp->coda_create.excl = excl;
2858c2ecf20Sopenharmony_ci        inp->coda_create.mode = mode;
2868c2ecf20Sopenharmony_ci        inp->coda_create.name = offset;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci        /* Venus must get null terminated string */
2898c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, name, length);
2908c2ecf20Sopenharmony_ci        *((char *)inp + offset + length) = '\0';
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
2938c2ecf20Sopenharmony_ci	if (!error) {
2948c2ecf20Sopenharmony_ci		*attrs = outp->coda_create.attr;
2958c2ecf20Sopenharmony_ci		*newfid = outp->coda_create.VFid;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	kvfree(inp);
2998c2ecf20Sopenharmony_ci	return error;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ciint venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
3038c2ecf20Sopenharmony_ci		    const char *name, int length)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci        union inputArgs *inp;
3068c2ecf20Sopenharmony_ci        union outputArgs *outp;
3078c2ecf20Sopenharmony_ci        int insize, outsize, error;
3088c2ecf20Sopenharmony_ci        int offset;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci        offset = INSIZE(rmdir);
3118c2ecf20Sopenharmony_ci	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
3128c2ecf20Sopenharmony_ci	UPARG(CODA_RMDIR);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci        inp->coda_rmdir.VFid = *dirfid;
3158c2ecf20Sopenharmony_ci        inp->coda_rmdir.name = offset;
3168c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, name, length);
3178c2ecf20Sopenharmony_ci	*((char *)inp + offset + length) = '\0';
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	kvfree(inp);
3228c2ecf20Sopenharmony_ci	return error;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ciint venus_remove(struct super_block *sb, struct CodaFid *dirfid,
3268c2ecf20Sopenharmony_ci		    const char *name, int length)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci        union inputArgs *inp;
3298c2ecf20Sopenharmony_ci        union outputArgs *outp;
3308c2ecf20Sopenharmony_ci        int error=0, insize, outsize, offset;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci        offset = INSIZE(remove);
3338c2ecf20Sopenharmony_ci	insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
3348c2ecf20Sopenharmony_ci	UPARG(CODA_REMOVE);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci        inp->coda_remove.VFid = *dirfid;
3378c2ecf20Sopenharmony_ci        inp->coda_remove.name = offset;
3388c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, name, length);
3398c2ecf20Sopenharmony_ci	*((char *)inp + offset + length) = '\0';
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	kvfree(inp);
3448c2ecf20Sopenharmony_ci	return error;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ciint venus_readlink(struct super_block *sb, struct CodaFid *fid,
3488c2ecf20Sopenharmony_ci		      char *buffer, int *length)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci        union inputArgs *inp;
3518c2ecf20Sopenharmony_ci        union outputArgs *outp;
3528c2ecf20Sopenharmony_ci        int insize, outsize, error;
3538c2ecf20Sopenharmony_ci        int retlen;
3548c2ecf20Sopenharmony_ci        char *result;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	insize = max_t(unsigned int,
3578c2ecf20Sopenharmony_ci		     INSIZE(readlink), OUTSIZE(readlink)+ *length);
3588c2ecf20Sopenharmony_ci	UPARG(CODA_READLINK);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci        inp->coda_readlink.VFid = *fid;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
3638c2ecf20Sopenharmony_ci	if (!error) {
3648c2ecf20Sopenharmony_ci		retlen = outp->coda_readlink.count;
3658c2ecf20Sopenharmony_ci		if (retlen >= *length)
3668c2ecf20Sopenharmony_ci			retlen = *length - 1;
3678c2ecf20Sopenharmony_ci		*length = retlen;
3688c2ecf20Sopenharmony_ci		result =  (char *)outp + (long)outp->coda_readlink.data;
3698c2ecf20Sopenharmony_ci		memcpy(buffer, result, retlen);
3708c2ecf20Sopenharmony_ci		*(buffer + retlen) = '\0';
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	kvfree(inp);
3748c2ecf20Sopenharmony_ci        return error;
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ciint venus_link(struct super_block *sb, struct CodaFid *fid,
3808c2ecf20Sopenharmony_ci		  struct CodaFid *dirfid, const char *name, int len )
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci        union inputArgs *inp;
3838c2ecf20Sopenharmony_ci        union outputArgs *outp;
3848c2ecf20Sopenharmony_ci        int insize, outsize, error;
3858c2ecf20Sopenharmony_ci        int offset;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	offset = INSIZE(link);
3888c2ecf20Sopenharmony_ci	insize = max_t(unsigned int, offset  + len + 1, OUTSIZE(link));
3898c2ecf20Sopenharmony_ci        UPARG(CODA_LINK);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci        inp->coda_link.sourceFid = *fid;
3928c2ecf20Sopenharmony_ci        inp->coda_link.destFid = *dirfid;
3938c2ecf20Sopenharmony_ci        inp->coda_link.tname = offset;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci        /* make sure strings are null terminated */
3968c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, name, len);
3978c2ecf20Sopenharmony_ci        *((char *)inp + offset + len) = '\0';
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	kvfree(inp);
4028c2ecf20Sopenharmony_ci        return error;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ciint venus_symlink(struct super_block *sb, struct CodaFid *fid,
4068c2ecf20Sopenharmony_ci		     const char *name, int len,
4078c2ecf20Sopenharmony_ci		     const char *symname, int symlen)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci        union inputArgs *inp;
4108c2ecf20Sopenharmony_ci        union outputArgs *outp;
4118c2ecf20Sopenharmony_ci        int insize, outsize, error;
4128c2ecf20Sopenharmony_ci        int offset, s;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci        offset = INSIZE(symlink);
4158c2ecf20Sopenharmony_ci	insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
4168c2ecf20Sopenharmony_ci	UPARG(CODA_SYMLINK);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci        /*        inp->coda_symlink.attr = *tva; XXXXXX */
4198c2ecf20Sopenharmony_ci        inp->coda_symlink.VFid = *fid;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	/* Round up to word boundary and null terminate */
4228c2ecf20Sopenharmony_ci        inp->coda_symlink.srcname = offset;
4238c2ecf20Sopenharmony_ci        s = ( symlen  & ~0x3 ) + 4;
4248c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, symname, symlen);
4258c2ecf20Sopenharmony_ci        *((char *)inp + offset + symlen) = '\0';
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/* Round up to word boundary and null terminate */
4288c2ecf20Sopenharmony_ci        offset += s;
4298c2ecf20Sopenharmony_ci        inp->coda_symlink.tname = offset;
4308c2ecf20Sopenharmony_ci        s = (len & ~0x3) + 4;
4318c2ecf20Sopenharmony_ci        memcpy((char *)(inp) + offset, name, len);
4328c2ecf20Sopenharmony_ci        *((char *)inp + offset + len) = '\0';
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	kvfree(inp);
4378c2ecf20Sopenharmony_ci        return error;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ciint venus_fsync(struct super_block *sb, struct CodaFid *fid)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci        union inputArgs *inp;
4438c2ecf20Sopenharmony_ci        union outputArgs *outp;
4448c2ecf20Sopenharmony_ci	int insize, outsize, error;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	insize=SIZE(fsync);
4478c2ecf20Sopenharmony_ci	UPARG(CODA_FSYNC);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	inp->coda_fsync.VFid = *fid;
4508c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	kvfree(inp);
4538c2ecf20Sopenharmony_ci	return error;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ciint venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci        union inputArgs *inp;
4598c2ecf20Sopenharmony_ci        union outputArgs *outp;
4608c2ecf20Sopenharmony_ci	int insize, outsize, error;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	insize = SIZE(access);
4638c2ecf20Sopenharmony_ci	UPARG(CODA_ACCESS);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci        inp->coda_access.VFid = *fid;
4668c2ecf20Sopenharmony_ci        inp->coda_access.flags = mask;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	kvfree(inp);
4718c2ecf20Sopenharmony_ci	return error;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ciint venus_pioctl(struct super_block *sb, struct CodaFid *fid,
4768c2ecf20Sopenharmony_ci		 unsigned int cmd, struct PioctlData *data)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci        union inputArgs *inp;
4798c2ecf20Sopenharmony_ci        union outputArgs *outp;
4808c2ecf20Sopenharmony_ci	int insize, outsize, error;
4818c2ecf20Sopenharmony_ci	int iocsize;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	insize = VC_MAXMSGSIZE;
4848c2ecf20Sopenharmony_ci	UPARG(CODA_IOCTL);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci        /* build packet for Venus */
4878c2ecf20Sopenharmony_ci        if (data->vi.in_size > VC_MAXDATASIZE) {
4888c2ecf20Sopenharmony_ci		error = -EINVAL;
4898c2ecf20Sopenharmony_ci		goto exit;
4908c2ecf20Sopenharmony_ci        }
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci        if (data->vi.out_size > VC_MAXDATASIZE) {
4938c2ecf20Sopenharmony_ci		error = -EINVAL;
4948c2ecf20Sopenharmony_ci		goto exit;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci        inp->coda_ioctl.VFid = *fid;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci        /* the cmd field was mutated by increasing its size field to
5008c2ecf20Sopenharmony_ci         * reflect the path and follow args. We need to subtract that
5018c2ecf20Sopenharmony_ci         * out before sending the command to Venus.  */
5028c2ecf20Sopenharmony_ci        inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
5038c2ecf20Sopenharmony_ci        iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
5048c2ecf20Sopenharmony_ci        inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<	16;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci        /* in->coda_ioctl.rwflag = flag; */
5078c2ecf20Sopenharmony_ci        inp->coda_ioctl.len = data->vi.in_size;
5088c2ecf20Sopenharmony_ci        inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci        /* get the data out of user space */
5118c2ecf20Sopenharmony_ci	if (copy_from_user((char *)inp + (long)inp->coda_ioctl.data,
5128c2ecf20Sopenharmony_ci			   data->vi.in, data->vi.in_size)) {
5138c2ecf20Sopenharmony_ci		error = -EINVAL;
5148c2ecf20Sopenharmony_ci	        goto exit;
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
5188c2ecf20Sopenharmony_ci			    &outsize, inp);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci        if (error) {
5218c2ecf20Sopenharmony_ci		pr_warn("%s: Venus returns: %d for %s\n",
5228c2ecf20Sopenharmony_ci			__func__, error, coda_f2s(fid));
5238c2ecf20Sopenharmony_ci		goto exit;
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
5278c2ecf20Sopenharmony_ci		error = -EINVAL;
5288c2ecf20Sopenharmony_ci		goto exit;
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/* Copy out the OUT buffer. */
5328c2ecf20Sopenharmony_ci        if (outp->coda_ioctl.len > data->vi.out_size) {
5338c2ecf20Sopenharmony_ci		error = -EINVAL;
5348c2ecf20Sopenharmony_ci		goto exit;
5358c2ecf20Sopenharmony_ci        }
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/* Copy out the OUT buffer. */
5388c2ecf20Sopenharmony_ci	if (copy_to_user(data->vi.out,
5398c2ecf20Sopenharmony_ci			 (char *)outp + (long)outp->coda_ioctl.data,
5408c2ecf20Sopenharmony_ci			 outp->coda_ioctl.len)) {
5418c2ecf20Sopenharmony_ci		error = -EFAULT;
5428c2ecf20Sopenharmony_ci		goto exit;
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci exit:
5468c2ecf20Sopenharmony_ci	kvfree(inp);
5478c2ecf20Sopenharmony_ci	return error;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ciint venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci        union inputArgs *inp;
5538c2ecf20Sopenharmony_ci        union outputArgs *outp;
5548c2ecf20Sopenharmony_ci        int insize, outsize, error;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	insize = SIZE(statfs);
5578c2ecf20Sopenharmony_ci	UPARG(CODA_STATFS);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
5608c2ecf20Sopenharmony_ci	if (!error) {
5618c2ecf20Sopenharmony_ci		sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
5628c2ecf20Sopenharmony_ci		sfs->f_bfree  = outp->coda_statfs.stat.f_bfree;
5638c2ecf20Sopenharmony_ci		sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
5648c2ecf20Sopenharmony_ci		sfs->f_files  = outp->coda_statfs.stat.f_files;
5658c2ecf20Sopenharmony_ci		sfs->f_ffree  = outp->coda_statfs.stat.f_ffree;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	kvfree(inp);
5698c2ecf20Sopenharmony_ci        return error;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ciint venus_access_intent(struct super_block *sb, struct CodaFid *fid,
5738c2ecf20Sopenharmony_ci			bool *access_intent_supported,
5748c2ecf20Sopenharmony_ci			size_t count, loff_t ppos, int type)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	union inputArgs *inp;
5778c2ecf20Sopenharmony_ci	union outputArgs *outp;
5788c2ecf20Sopenharmony_ci	int insize, outsize, error;
5798c2ecf20Sopenharmony_ci	bool finalizer =
5808c2ecf20Sopenharmony_ci		type == CODA_ACCESS_TYPE_READ_FINISH ||
5818c2ecf20Sopenharmony_ci		type == CODA_ACCESS_TYPE_WRITE_FINISH;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	if (!*access_intent_supported && !finalizer)
5848c2ecf20Sopenharmony_ci		return 0;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	insize = SIZE(access_intent);
5878c2ecf20Sopenharmony_ci	UPARG(CODA_ACCESS_INTENT);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	inp->coda_access_intent.VFid = *fid;
5908c2ecf20Sopenharmony_ci	inp->coda_access_intent.count = count;
5918c2ecf20Sopenharmony_ci	inp->coda_access_intent.pos = ppos;
5928c2ecf20Sopenharmony_ci	inp->coda_access_intent.type = type;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	error = coda_upcall(coda_vcp(sb), insize,
5958c2ecf20Sopenharmony_ci			    finalizer ? NULL : &outsize, inp);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/*
5988c2ecf20Sopenharmony_ci	 * we have to free the request buffer for synchronous upcalls
5998c2ecf20Sopenharmony_ci	 * or when asynchronous upcalls fail, but not when asynchronous
6008c2ecf20Sopenharmony_ci	 * upcalls succeed
6018c2ecf20Sopenharmony_ci	 */
6028c2ecf20Sopenharmony_ci	if (!finalizer || error)
6038c2ecf20Sopenharmony_ci		kvfree(inp);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	/* Chunked access is not supported or an old Coda client */
6068c2ecf20Sopenharmony_ci	if (error == -EOPNOTSUPP) {
6078c2ecf20Sopenharmony_ci		*access_intent_supported = false;
6088c2ecf20Sopenharmony_ci		error = 0;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci	return error;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci/*
6148c2ecf20Sopenharmony_ci * coda_upcall and coda_downcall routines.
6158c2ecf20Sopenharmony_ci */
6168c2ecf20Sopenharmony_cistatic void coda_block_signals(sigset_t *old)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	spin_lock_irq(&current->sighand->siglock);
6198c2ecf20Sopenharmony_ci	*old = current->blocked;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	sigfillset(&current->blocked);
6228c2ecf20Sopenharmony_ci	sigdelset(&current->blocked, SIGKILL);
6238c2ecf20Sopenharmony_ci	sigdelset(&current->blocked, SIGSTOP);
6248c2ecf20Sopenharmony_ci	sigdelset(&current->blocked, SIGINT);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	recalc_sigpending();
6278c2ecf20Sopenharmony_ci	spin_unlock_irq(&current->sighand->siglock);
6288c2ecf20Sopenharmony_ci}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_cistatic void coda_unblock_signals(sigset_t *old)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	spin_lock_irq(&current->sighand->siglock);
6338c2ecf20Sopenharmony_ci	current->blocked = *old;
6348c2ecf20Sopenharmony_ci	recalc_sigpending();
6358c2ecf20Sopenharmony_ci	spin_unlock_irq(&current->sighand->siglock);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci/* Don't allow signals to interrupt the following upcalls before venus
6398c2ecf20Sopenharmony_ci * has seen them,
6408c2ecf20Sopenharmony_ci * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
6418c2ecf20Sopenharmony_ci * - CODA_STORE				(to avoid data loss)
6428c2ecf20Sopenharmony_ci * - CODA_ACCESS_INTENT                 (to avoid reference count problems)
6438c2ecf20Sopenharmony_ci */
6448c2ecf20Sopenharmony_ci#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
6458c2ecf20Sopenharmony_ci			       (((r)->uc_opcode != CODA_CLOSE && \
6468c2ecf20Sopenharmony_ci				 (r)->uc_opcode != CODA_STORE && \
6478c2ecf20Sopenharmony_ci				 (r)->uc_opcode != CODA_ACCESS_INTENT && \
6488c2ecf20Sopenharmony_ci				 (r)->uc_opcode != CODA_RELEASE) || \
6498c2ecf20Sopenharmony_ci				(r)->uc_flags & CODA_REQ_READ))
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_cistatic inline void coda_waitfor_upcall(struct venus_comm *vcp,
6528c2ecf20Sopenharmony_ci				       struct upc_req *req)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	DECLARE_WAITQUEUE(wait, current);
6558c2ecf20Sopenharmony_ci	unsigned long timeout = jiffies + coda_timeout * HZ;
6568c2ecf20Sopenharmony_ci	sigset_t old;
6578c2ecf20Sopenharmony_ci	int blocked;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	coda_block_signals(&old);
6608c2ecf20Sopenharmony_ci	blocked = 1;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	add_wait_queue(&req->uc_sleep, &wait);
6638c2ecf20Sopenharmony_ci	for (;;) {
6648c2ecf20Sopenharmony_ci		if (CODA_INTERRUPTIBLE(req))
6658c2ecf20Sopenharmony_ci			set_current_state(TASK_INTERRUPTIBLE);
6668c2ecf20Sopenharmony_ci		else
6678c2ecf20Sopenharmony_ci			set_current_state(TASK_UNINTERRUPTIBLE);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci		/* got a reply */
6708c2ecf20Sopenharmony_ci		if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT))
6718c2ecf20Sopenharmony_ci			break;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci		if (blocked && time_after(jiffies, timeout) &&
6748c2ecf20Sopenharmony_ci		    CODA_INTERRUPTIBLE(req))
6758c2ecf20Sopenharmony_ci		{
6768c2ecf20Sopenharmony_ci			coda_unblock_signals(&old);
6778c2ecf20Sopenharmony_ci			blocked = 0;
6788c2ecf20Sopenharmony_ci		}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci		if (signal_pending(current)) {
6818c2ecf20Sopenharmony_ci			list_del(&req->uc_chain);
6828c2ecf20Sopenharmony_ci			break;
6838c2ecf20Sopenharmony_ci		}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		mutex_unlock(&vcp->vc_mutex);
6868c2ecf20Sopenharmony_ci		if (blocked)
6878c2ecf20Sopenharmony_ci			schedule_timeout(HZ);
6888c2ecf20Sopenharmony_ci		else
6898c2ecf20Sopenharmony_ci			schedule();
6908c2ecf20Sopenharmony_ci		mutex_lock(&vcp->vc_mutex);
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci	if (blocked)
6938c2ecf20Sopenharmony_ci		coda_unblock_signals(&old);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	remove_wait_queue(&req->uc_sleep, &wait);
6968c2ecf20Sopenharmony_ci	set_current_state(TASK_RUNNING);
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci/*
7018c2ecf20Sopenharmony_ci * coda_upcall will return an error in the case of
7028c2ecf20Sopenharmony_ci * failed communication with Venus _or_ will peek at Venus
7038c2ecf20Sopenharmony_ci * reply and return Venus' error.
7048c2ecf20Sopenharmony_ci *
7058c2ecf20Sopenharmony_ci * As venus has 2 types of errors, normal errors (positive) and internal
7068c2ecf20Sopenharmony_ci * errors (negative), normal errors are negated, while internal errors
7078c2ecf20Sopenharmony_ci * are all mapped to -EINTR, while showing a nice warning message. (jh)
7088c2ecf20Sopenharmony_ci */
7098c2ecf20Sopenharmony_cistatic int coda_upcall(struct venus_comm *vcp,
7108c2ecf20Sopenharmony_ci		       int inSize, int *outSize,
7118c2ecf20Sopenharmony_ci		       union inputArgs *buffer)
7128c2ecf20Sopenharmony_ci{
7138c2ecf20Sopenharmony_ci	union outputArgs *out;
7148c2ecf20Sopenharmony_ci	union inputArgs *sig_inputArgs;
7158c2ecf20Sopenharmony_ci	struct upc_req *req = NULL, *sig_req;
7168c2ecf20Sopenharmony_ci	int error;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	mutex_lock(&vcp->vc_mutex);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	if (!vcp->vc_inuse) {
7218c2ecf20Sopenharmony_ci		pr_notice("Venus dead, not sending upcall\n");
7228c2ecf20Sopenharmony_ci		error = -ENXIO;
7238c2ecf20Sopenharmony_ci		goto exit;
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	/* Format the request message. */
7278c2ecf20Sopenharmony_ci	req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
7288c2ecf20Sopenharmony_ci	if (!req) {
7298c2ecf20Sopenharmony_ci		error = -ENOMEM;
7308c2ecf20Sopenharmony_ci		goto exit;
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	buffer->ih.unique = ++vcp->vc_seq;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	req->uc_data = (void *)buffer;
7368c2ecf20Sopenharmony_ci	req->uc_flags = outSize ? 0 : CODA_REQ_ASYNC;
7378c2ecf20Sopenharmony_ci	req->uc_inSize = inSize;
7388c2ecf20Sopenharmony_ci	req->uc_outSize = (outSize && *outSize) ? *outSize : inSize;
7398c2ecf20Sopenharmony_ci	req->uc_opcode = buffer->ih.opcode;
7408c2ecf20Sopenharmony_ci	req->uc_unique = buffer->ih.unique;
7418c2ecf20Sopenharmony_ci	init_waitqueue_head(&req->uc_sleep);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	/* Append msg to pending queue and poke Venus. */
7448c2ecf20Sopenharmony_ci	list_add_tail(&req->uc_chain, &vcp->vc_pending);
7458c2ecf20Sopenharmony_ci	wake_up_interruptible(&vcp->vc_waitq);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	if (req->uc_flags & CODA_REQ_ASYNC) {
7488c2ecf20Sopenharmony_ci		mutex_unlock(&vcp->vc_mutex);
7498c2ecf20Sopenharmony_ci		return 0;
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	/* We can be interrupted while we wait for Venus to process
7538c2ecf20Sopenharmony_ci	 * our request.  If the interrupt occurs before Venus has read
7548c2ecf20Sopenharmony_ci	 * the request, we dequeue and return. If it occurs after the
7558c2ecf20Sopenharmony_ci	 * read but before the reply, we dequeue, send a signal
7568c2ecf20Sopenharmony_ci	 * message, and return. If it occurs after the reply we ignore
7578c2ecf20Sopenharmony_ci	 * it. In no case do we want to restart the syscall.  If it
7588c2ecf20Sopenharmony_ci	 * was interrupted by a venus shutdown (psdev_close), return
7598c2ecf20Sopenharmony_ci	 * ENODEV.  */
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	/* Go to sleep.  Wake up on signals only after the timeout. */
7628c2ecf20Sopenharmony_ci	coda_waitfor_upcall(vcp, req);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	/* Op went through, interrupt or not... */
7658c2ecf20Sopenharmony_ci	if (req->uc_flags & CODA_REQ_WRITE) {
7668c2ecf20Sopenharmony_ci		out = (union outputArgs *)req->uc_data;
7678c2ecf20Sopenharmony_ci		/* here we map positive Venus errors to kernel errors */
7688c2ecf20Sopenharmony_ci		error = -out->oh.result;
7698c2ecf20Sopenharmony_ci		*outSize = req->uc_outSize;
7708c2ecf20Sopenharmony_ci		goto exit;
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	error = -EINTR;
7748c2ecf20Sopenharmony_ci	if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) {
7758c2ecf20Sopenharmony_ci		pr_warn("Unexpected interruption.\n");
7768c2ecf20Sopenharmony_ci		goto exit;
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	/* Interrupted before venus read it. */
7808c2ecf20Sopenharmony_ci	if (!(req->uc_flags & CODA_REQ_READ))
7818c2ecf20Sopenharmony_ci		goto exit;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	/* Venus saw the upcall, make sure we can send interrupt signal */
7848c2ecf20Sopenharmony_ci	if (!vcp->vc_inuse) {
7858c2ecf20Sopenharmony_ci		pr_info("Venus dead, not sending signal.\n");
7868c2ecf20Sopenharmony_ci		goto exit;
7878c2ecf20Sopenharmony_ci	}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	error = -ENOMEM;
7908c2ecf20Sopenharmony_ci	sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
7918c2ecf20Sopenharmony_ci	if (!sig_req) goto exit;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	sig_inputArgs = kvzalloc(sizeof(*sig_inputArgs), GFP_KERNEL);
7948c2ecf20Sopenharmony_ci	if (!sig_inputArgs) {
7958c2ecf20Sopenharmony_ci		kfree(sig_req);
7968c2ecf20Sopenharmony_ci		goto exit;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	error = -EINTR;
8008c2ecf20Sopenharmony_ci	sig_inputArgs->ih.opcode = CODA_SIGNAL;
8018c2ecf20Sopenharmony_ci	sig_inputArgs->ih.unique = req->uc_unique;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	sig_req->uc_flags = CODA_REQ_ASYNC;
8048c2ecf20Sopenharmony_ci	sig_req->uc_opcode = sig_inputArgs->ih.opcode;
8058c2ecf20Sopenharmony_ci	sig_req->uc_unique = sig_inputArgs->ih.unique;
8068c2ecf20Sopenharmony_ci	sig_req->uc_data = (void *)sig_inputArgs;
8078c2ecf20Sopenharmony_ci	sig_req->uc_inSize = sizeof(struct coda_in_hdr);
8088c2ecf20Sopenharmony_ci	sig_req->uc_outSize = sizeof(struct coda_in_hdr);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	/* insert at head of queue! */
8118c2ecf20Sopenharmony_ci	list_add(&(sig_req->uc_chain), &vcp->vc_pending);
8128c2ecf20Sopenharmony_ci	wake_up_interruptible(&vcp->vc_waitq);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ciexit:
8158c2ecf20Sopenharmony_ci	kfree(req);
8168c2ecf20Sopenharmony_ci	mutex_unlock(&vcp->vc_mutex);
8178c2ecf20Sopenharmony_ci	return error;
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci/*
8218c2ecf20Sopenharmony_ci    The statements below are part of the Coda opportunistic
8228c2ecf20Sopenharmony_ci    programming -- taken from the Mach/BSD kernel code for Coda.
8238c2ecf20Sopenharmony_ci    You don't get correct semantics by stating what needs to be
8248c2ecf20Sopenharmony_ci    done without guaranteeing the invariants needed for it to happen.
8258c2ecf20Sopenharmony_ci    When will be have time to find out what exactly is going on?  (pjb)
8268c2ecf20Sopenharmony_ci*/
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci/*
8308c2ecf20Sopenharmony_ci * There are 7 cases where cache invalidations occur.  The semantics
8318c2ecf20Sopenharmony_ci *  of each is listed here:
8328c2ecf20Sopenharmony_ci *
8338c2ecf20Sopenharmony_ci * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
8348c2ecf20Sopenharmony_ci * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
8358c2ecf20Sopenharmony_ci *                  This call is a result of token expiration.
8368c2ecf20Sopenharmony_ci *
8378c2ecf20Sopenharmony_ci * The next arise as the result of callbacks on a file or directory.
8388c2ecf20Sopenharmony_ci * CODA_ZAPFILE   -- flush the cached attributes for a file.
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci * CODA_ZAPDIR    -- flush the attributes for the dir and
8418c2ecf20Sopenharmony_ci *                  force a new lookup for all the children
8428c2ecf20Sopenharmony_ci                    of this dir.
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci *
8458c2ecf20Sopenharmony_ci * The next is a result of Venus detecting an inconsistent file.
8468c2ecf20Sopenharmony_ci * CODA_PURGEFID  -- flush the attribute for the file
8478c2ecf20Sopenharmony_ci *                  purge it and its children from the dcache
8488c2ecf20Sopenharmony_ci *
8498c2ecf20Sopenharmony_ci * The last  allows Venus to replace local fids with global ones
8508c2ecf20Sopenharmony_ci * during reintegration.
8518c2ecf20Sopenharmony_ci *
8528c2ecf20Sopenharmony_ci * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ciint coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out,
8558c2ecf20Sopenharmony_ci		  size_t nbytes)
8568c2ecf20Sopenharmony_ci{
8578c2ecf20Sopenharmony_ci	struct inode *inode = NULL;
8588c2ecf20Sopenharmony_ci	struct CodaFid *fid = NULL, *newfid;
8598c2ecf20Sopenharmony_ci	struct super_block *sb;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	/*
8628c2ecf20Sopenharmony_ci	 * Make sure we have received enough data from the cache
8638c2ecf20Sopenharmony_ci	 * manager to populate the necessary fields in the buffer
8648c2ecf20Sopenharmony_ci	 */
8658c2ecf20Sopenharmony_ci	switch (opcode) {
8668c2ecf20Sopenharmony_ci	case CODA_PURGEUSER:
8678c2ecf20Sopenharmony_ci		if (nbytes < sizeof(struct coda_purgeuser_out))
8688c2ecf20Sopenharmony_ci			return -EINVAL;
8698c2ecf20Sopenharmony_ci		break;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	case CODA_ZAPDIR:
8728c2ecf20Sopenharmony_ci		if (nbytes < sizeof(struct coda_zapdir_out))
8738c2ecf20Sopenharmony_ci			return -EINVAL;
8748c2ecf20Sopenharmony_ci		break;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	case CODA_ZAPFILE:
8778c2ecf20Sopenharmony_ci		if (nbytes < sizeof(struct coda_zapfile_out))
8788c2ecf20Sopenharmony_ci			return -EINVAL;
8798c2ecf20Sopenharmony_ci		break;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	case CODA_PURGEFID:
8828c2ecf20Sopenharmony_ci		if (nbytes < sizeof(struct coda_purgefid_out))
8838c2ecf20Sopenharmony_ci			return -EINVAL;
8848c2ecf20Sopenharmony_ci		break;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	case CODA_REPLACE:
8878c2ecf20Sopenharmony_ci		if (nbytes < sizeof(struct coda_replace_out))
8888c2ecf20Sopenharmony_ci			return -EINVAL;
8898c2ecf20Sopenharmony_ci		break;
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	/* Handle invalidation requests. */
8938c2ecf20Sopenharmony_ci	mutex_lock(&vcp->vc_mutex);
8948c2ecf20Sopenharmony_ci	sb = vcp->vc_sb;
8958c2ecf20Sopenharmony_ci	if (!sb || !sb->s_root)
8968c2ecf20Sopenharmony_ci		goto unlock_out;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	switch (opcode) {
8998c2ecf20Sopenharmony_ci	case CODA_FLUSH:
9008c2ecf20Sopenharmony_ci		coda_cache_clear_all(sb);
9018c2ecf20Sopenharmony_ci		shrink_dcache_sb(sb);
9028c2ecf20Sopenharmony_ci		if (d_really_is_positive(sb->s_root))
9038c2ecf20Sopenharmony_ci			coda_flag_inode(d_inode(sb->s_root), C_FLUSH);
9048c2ecf20Sopenharmony_ci		break;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	case CODA_PURGEUSER:
9078c2ecf20Sopenharmony_ci		coda_cache_clear_all(sb);
9088c2ecf20Sopenharmony_ci		break;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	case CODA_ZAPDIR:
9118c2ecf20Sopenharmony_ci		fid = &out->coda_zapdir.CodaFid;
9128c2ecf20Sopenharmony_ci		break;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	case CODA_ZAPFILE:
9158c2ecf20Sopenharmony_ci		fid = &out->coda_zapfile.CodaFid;
9168c2ecf20Sopenharmony_ci		break;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	case CODA_PURGEFID:
9198c2ecf20Sopenharmony_ci		fid = &out->coda_purgefid.CodaFid;
9208c2ecf20Sopenharmony_ci		break;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	case CODA_REPLACE:
9238c2ecf20Sopenharmony_ci		fid = &out->coda_replace.OldFid;
9248c2ecf20Sopenharmony_ci		break;
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci	if (fid)
9278c2ecf20Sopenharmony_ci		inode = coda_fid_to_inode(fid, sb);
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ciunlock_out:
9308c2ecf20Sopenharmony_ci	mutex_unlock(&vcp->vc_mutex);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	if (!inode)
9338c2ecf20Sopenharmony_ci		return 0;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	switch (opcode) {
9368c2ecf20Sopenharmony_ci	case CODA_ZAPDIR:
9378c2ecf20Sopenharmony_ci		coda_flag_inode_children(inode, C_PURGE);
9388c2ecf20Sopenharmony_ci		coda_flag_inode(inode, C_VATTR);
9398c2ecf20Sopenharmony_ci		break;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	case CODA_ZAPFILE:
9428c2ecf20Sopenharmony_ci		coda_flag_inode(inode, C_VATTR);
9438c2ecf20Sopenharmony_ci		break;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	case CODA_PURGEFID:
9468c2ecf20Sopenharmony_ci		coda_flag_inode_children(inode, C_PURGE);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci		/* catch the dentries later if some are still busy */
9498c2ecf20Sopenharmony_ci		coda_flag_inode(inode, C_PURGE);
9508c2ecf20Sopenharmony_ci		d_prune_aliases(inode);
9518c2ecf20Sopenharmony_ci		break;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	case CODA_REPLACE:
9548c2ecf20Sopenharmony_ci		newfid = &out->coda_replace.NewFid;
9558c2ecf20Sopenharmony_ci		coda_replace_fid(inode, fid, newfid);
9568c2ecf20Sopenharmony_ci		break;
9578c2ecf20Sopenharmony_ci	}
9588c2ecf20Sopenharmony_ci	iput(inode);
9598c2ecf20Sopenharmony_ci	return 0;
9608c2ecf20Sopenharmony_ci}
961