1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Mostly platform independent upcall operations to Venus: 41da177e4SLinus Torvalds * -- upcalls 51da177e4SLinus Torvalds * -- upcall routines 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Linux 2.0 version 81da177e4SLinus Torvalds * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>, 91da177e4SLinus Torvalds * Michael Callahan <callahan@maths.ox.ac.uk> 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * Redone for Linux 2.1 121da177e4SLinus Torvalds * Copyright (C) 1997 Carnegie Mellon University 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * Carnegie Mellon University encourages users of this code to contribute 151da177e4SLinus Torvalds * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>. 161da177e4SLinus Torvalds */ 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds #include <linux/signal.h> 193f07c014SIngo Molnar #include <linux/sched/signal.h> 201da177e4SLinus Torvalds #include <linux/types.h> 211da177e4SLinus Torvalds #include <linux/kernel.h> 221da177e4SLinus Torvalds #include <linux/mm.h> 231da177e4SLinus Torvalds #include <linux/time.h> 241da177e4SLinus Torvalds #include <linux/fs.h> 251da177e4SLinus Torvalds #include <linux/file.h> 261da177e4SLinus Torvalds #include <linux/stat.h> 271da177e4SLinus Torvalds #include <linux/errno.h> 281da177e4SLinus Torvalds #include <linux/string.h> 295a0e3ad6STejun Heo #include <linux/slab.h> 30da47c19eSYoshihisa Abe #include <linux/mutex.h> 31834b46c3SFabian Frederick #include <linux/uaccess.h> 321da177e4SLinus Torvalds #include <linux/vmalloc.h> 331da177e4SLinus Torvalds #include <linux/vfs.h> 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds #include <linux/coda.h> 361da177e4SLinus Torvalds #include <linux/coda_psdev.h> 3731a203dfSAl Viro #include "coda_linux.h" 3831a203dfSAl Viro #include "coda_cache.h" 393cf01f28SJan Harkes 403cf01f28SJan Harkes #include "coda_int.h" 411da177e4SLinus Torvalds 42a1b0aa87SJan Harkes static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize, 431da177e4SLinus Torvalds union inputArgs *buffer); 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds static void *alloc_upcall(int opcode, int size) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds union inputArgs *inp; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds CODA_ALLOC(inp, union inputArgs *, size); 501da177e4SLinus Torvalds if (!inp) 511da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds inp->ih.opcode = opcode; 549fd973e0SEric W. Biederman inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns); 559fd973e0SEric W. Biederman inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns); 56d83f5901SEric W. Biederman inp->ih.uid = from_kuid(&init_user_ns, current_fsuid()); 57de0ca06aSAdrian Bunk 581da177e4SLinus Torvalds return (void*)inp; 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #define UPARG(op)\ 621da177e4SLinus Torvalds do {\ 631da177e4SLinus Torvalds inp = (union inputArgs *)alloc_upcall(op, insize); \ 641da177e4SLinus Torvalds if (IS_ERR(inp)) { return PTR_ERR(inp); }\ 651da177e4SLinus Torvalds outp = (union outputArgs *)(inp); \ 661da177e4SLinus Torvalds outsize = insize; \ 671da177e4SLinus Torvalds } while (0) 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in) 701da177e4SLinus Torvalds #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out) 711da177e4SLinus Torvalds #define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag)) 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds /* the upcalls */ 751da177e4SLinus Torvalds int venus_rootfid(struct super_block *sb, struct CodaFid *fidp) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds union inputArgs *inp; 781da177e4SLinus Torvalds union outputArgs *outp; 791da177e4SLinus Torvalds int insize, outsize, error; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds insize = SIZE(root); 821da177e4SLinus Torvalds UPARG(CODA_ROOT); 831da177e4SLinus Torvalds 84a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 85970648ebSJan Harkes if (!error) 861da177e4SLinus Torvalds *fidp = outp->coda_root.VFid; 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds CODA_FREE(inp, insize); 891da177e4SLinus Torvalds return error; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds int venus_getattr(struct super_block *sb, struct CodaFid *fid, 931da177e4SLinus Torvalds struct coda_vattr *attr) 941da177e4SLinus Torvalds { 951da177e4SLinus Torvalds union inputArgs *inp; 961da177e4SLinus Torvalds union outputArgs *outp; 971da177e4SLinus Torvalds int insize, outsize, error; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds insize = SIZE(getattr); 1001da177e4SLinus Torvalds UPARG(CODA_GETATTR); 1011da177e4SLinus Torvalds inp->coda_getattr.VFid = *fid; 1021da177e4SLinus Torvalds 103a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 104970648ebSJan Harkes if (!error) 1051da177e4SLinus Torvalds *attr = outp->coda_getattr.attr; 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds CODA_FREE(inp, insize); 1081da177e4SLinus Torvalds return error; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds int venus_setattr(struct super_block *sb, struct CodaFid *fid, 1121da177e4SLinus Torvalds struct coda_vattr *vattr) 1131da177e4SLinus Torvalds { 1141da177e4SLinus Torvalds union inputArgs *inp; 1151da177e4SLinus Torvalds union outputArgs *outp; 1161da177e4SLinus Torvalds int insize, outsize, error; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds insize = SIZE(setattr); 1191da177e4SLinus Torvalds UPARG(CODA_SETATTR); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds inp->coda_setattr.VFid = *fid; 1221da177e4SLinus Torvalds inp->coda_setattr.attr = *vattr; 1231da177e4SLinus Torvalds 124a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds CODA_FREE(inp, insize); 1271da177e4SLinus Torvalds return error; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds int venus_lookup(struct super_block *sb, struct CodaFid *fid, 1311da177e4SLinus Torvalds const char *name, int length, int * type, 1321da177e4SLinus Torvalds struct CodaFid *resfid) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds union inputArgs *inp; 1351da177e4SLinus Torvalds union outputArgs *outp; 1361da177e4SLinus Torvalds int insize, outsize, error; 1371da177e4SLinus Torvalds int offset; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds offset = INSIZE(lookup); 1401da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup)); 1411da177e4SLinus Torvalds UPARG(CODA_LOOKUP); 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds inp->coda_lookup.VFid = *fid; 1441da177e4SLinus Torvalds inp->coda_lookup.name = offset; 1451da177e4SLinus Torvalds inp->coda_lookup.flags = CLU_CASE_SENSITIVE; 1461da177e4SLinus Torvalds /* send Venus a null terminated string */ 1471da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 1481da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 1491da177e4SLinus Torvalds 150a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 151970648ebSJan Harkes if (!error) { 1521da177e4SLinus Torvalds *resfid = outp->coda_lookup.VFid; 1531da177e4SLinus Torvalds *type = outp->coda_lookup.vtype; 154970648ebSJan Harkes } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds CODA_FREE(inp, insize); 1571da177e4SLinus Torvalds return error; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds int venus_close(struct super_block *sb, struct CodaFid *fid, int flags, 161d83f5901SEric W. Biederman kuid_t uid) 1621da177e4SLinus Torvalds { 1631da177e4SLinus Torvalds union inputArgs *inp; 1641da177e4SLinus Torvalds union outputArgs *outp; 1651da177e4SLinus Torvalds int insize, outsize, error; 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds insize = SIZE(release); 1681da177e4SLinus Torvalds UPARG(CODA_CLOSE); 1691da177e4SLinus Torvalds 170d83f5901SEric W. Biederman inp->ih.uid = from_kuid(&init_user_ns, uid); 1711da177e4SLinus Torvalds inp->coda_close.VFid = *fid; 1721da177e4SLinus Torvalds inp->coda_close.flags = flags; 1731da177e4SLinus Torvalds 174a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds CODA_FREE(inp, insize); 1771da177e4SLinus Torvalds return error; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds int venus_open(struct super_block *sb, struct CodaFid *fid, 1811da177e4SLinus Torvalds int flags, struct file **fh) 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds union inputArgs *inp; 1841da177e4SLinus Torvalds union outputArgs *outp; 1851da177e4SLinus Torvalds int insize, outsize, error; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds insize = SIZE(open_by_fd); 1881da177e4SLinus Torvalds UPARG(CODA_OPEN_BY_FD); 1891da177e4SLinus Torvalds 19038c2e437SJan Harkes inp->coda_open_by_fd.VFid = *fid; 19138c2e437SJan Harkes inp->coda_open_by_fd.flags = flags; 1921da177e4SLinus Torvalds 193a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 19438c2e437SJan Harkes if (!error) 1951da177e4SLinus Torvalds *fh = outp->coda_open_by_fd.fh; 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds CODA_FREE(inp, insize); 1981da177e4SLinus Torvalds return error; 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, 2021da177e4SLinus Torvalds const char *name, int length, 2031da177e4SLinus Torvalds struct CodaFid *newfid, struct coda_vattr *attrs) 2041da177e4SLinus Torvalds { 2051da177e4SLinus Torvalds union inputArgs *inp; 2061da177e4SLinus Torvalds union outputArgs *outp; 2071da177e4SLinus Torvalds int insize, outsize, error; 2081da177e4SLinus Torvalds int offset; 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds offset = INSIZE(mkdir); 2111da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir)); 2121da177e4SLinus Torvalds UPARG(CODA_MKDIR); 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds inp->coda_mkdir.VFid = *dirfid; 2151da177e4SLinus Torvalds inp->coda_mkdir.attr = *attrs; 2161da177e4SLinus Torvalds inp->coda_mkdir.name = offset; 2171da177e4SLinus Torvalds /* Venus must get null terminated string */ 2181da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 2191da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 2201da177e4SLinus Torvalds 221a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 222970648ebSJan Harkes if (!error) { 2231da177e4SLinus Torvalds *attrs = outp->coda_mkdir.attr; 2241da177e4SLinus Torvalds *newfid = outp->coda_mkdir.VFid; 225970648ebSJan Harkes } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds CODA_FREE(inp, insize); 2281da177e4SLinus Torvalds return error; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds int venus_rename(struct super_block *sb, struct CodaFid *old_fid, 2331da177e4SLinus Torvalds struct CodaFid *new_fid, size_t old_length, 2341da177e4SLinus Torvalds size_t new_length, const char *old_name, 2351da177e4SLinus Torvalds const char *new_name) 2361da177e4SLinus Torvalds { 2371da177e4SLinus Torvalds union inputArgs *inp; 2381da177e4SLinus Torvalds union outputArgs *outp; 2391da177e4SLinus Torvalds int insize, outsize, error; 2401da177e4SLinus Torvalds int offset, s; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds offset = INSIZE(rename); 2431da177e4SLinus Torvalds insize = max_t(unsigned int, offset + new_length + old_length + 8, 2441da177e4SLinus Torvalds OUTSIZE(rename)); 2451da177e4SLinus Torvalds UPARG(CODA_RENAME); 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds inp->coda_rename.sourceFid = *old_fid; 2481da177e4SLinus Torvalds inp->coda_rename.destFid = *new_fid; 2491da177e4SLinus Torvalds inp->coda_rename.srcname = offset; 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds /* Venus must receive an null terminated string */ 2521da177e4SLinus Torvalds s = ( old_length & ~0x3) +4; /* round up to word boundary */ 2531da177e4SLinus Torvalds memcpy((char *)(inp) + offset, old_name, old_length); 2541da177e4SLinus Torvalds *((char *)inp + offset + old_length) = '\0'; 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds /* another null terminated string for Venus */ 2571da177e4SLinus Torvalds offset += s; 2581da177e4SLinus Torvalds inp->coda_rename.destname = offset; 2591da177e4SLinus Torvalds s = ( new_length & ~0x3) +4; /* round up to word boundary */ 2601da177e4SLinus Torvalds memcpy((char *)(inp) + offset, new_name, new_length); 2611da177e4SLinus Torvalds *((char *)inp + offset + new_length) = '\0'; 2621da177e4SLinus Torvalds 263a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds CODA_FREE(inp, insize); 2661da177e4SLinus Torvalds return error; 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds int venus_create(struct super_block *sb, struct CodaFid *dirfid, 2701da177e4SLinus Torvalds const char *name, int length, int excl, int mode, 2711da177e4SLinus Torvalds struct CodaFid *newfid, struct coda_vattr *attrs) 2721da177e4SLinus Torvalds { 2731da177e4SLinus Torvalds union inputArgs *inp; 2741da177e4SLinus Torvalds union outputArgs *outp; 2751da177e4SLinus Torvalds int insize, outsize, error; 2761da177e4SLinus Torvalds int offset; 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds offset = INSIZE(create); 2791da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create)); 2801da177e4SLinus Torvalds UPARG(CODA_CREATE); 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds inp->coda_create.VFid = *dirfid; 2831da177e4SLinus Torvalds inp->coda_create.attr.va_mode = mode; 2841da177e4SLinus Torvalds inp->coda_create.excl = excl; 2851da177e4SLinus Torvalds inp->coda_create.mode = mode; 2861da177e4SLinus Torvalds inp->coda_create.name = offset; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds /* Venus must get null terminated string */ 2891da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 2901da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 2911da177e4SLinus Torvalds 292a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 293970648ebSJan Harkes if (!error) { 2941da177e4SLinus Torvalds *attrs = outp->coda_create.attr; 2951da177e4SLinus Torvalds *newfid = outp->coda_create.VFid; 296970648ebSJan Harkes } 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds CODA_FREE(inp, insize); 2991da177e4SLinus Torvalds return error; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, 3031da177e4SLinus Torvalds const char *name, int length) 3041da177e4SLinus Torvalds { 3051da177e4SLinus Torvalds union inputArgs *inp; 3061da177e4SLinus Torvalds union outputArgs *outp; 3071da177e4SLinus Torvalds int insize, outsize, error; 3081da177e4SLinus Torvalds int offset; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds offset = INSIZE(rmdir); 3111da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir)); 3121da177e4SLinus Torvalds UPARG(CODA_RMDIR); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds inp->coda_rmdir.VFid = *dirfid; 3151da177e4SLinus Torvalds inp->coda_rmdir.name = offset; 3161da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 3171da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 3181da177e4SLinus Torvalds 319a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds CODA_FREE(inp, insize); 3221da177e4SLinus Torvalds return error; 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds int venus_remove(struct super_block *sb, struct CodaFid *dirfid, 3261da177e4SLinus Torvalds const char *name, int length) 3271da177e4SLinus Torvalds { 3281da177e4SLinus Torvalds union inputArgs *inp; 3291da177e4SLinus Torvalds union outputArgs *outp; 3301da177e4SLinus Torvalds int error=0, insize, outsize, offset; 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds offset = INSIZE(remove); 3331da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove)); 3341da177e4SLinus Torvalds UPARG(CODA_REMOVE); 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds inp->coda_remove.VFid = *dirfid; 3371da177e4SLinus Torvalds inp->coda_remove.name = offset; 3381da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 3391da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 3401da177e4SLinus Torvalds 341a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds CODA_FREE(inp, insize); 3441da177e4SLinus Torvalds return error; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds int venus_readlink(struct super_block *sb, struct CodaFid *fid, 3481da177e4SLinus Torvalds char *buffer, int *length) 3491da177e4SLinus Torvalds { 3501da177e4SLinus Torvalds union inputArgs *inp; 3511da177e4SLinus Torvalds union outputArgs *outp; 3521da177e4SLinus Torvalds int insize, outsize, error; 3531da177e4SLinus Torvalds int retlen; 3541da177e4SLinus Torvalds char *result; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds insize = max_t(unsigned int, 3573725e9ddSJan Harkes INSIZE(readlink), OUTSIZE(readlink)+ *length); 3581da177e4SLinus Torvalds UPARG(CODA_READLINK); 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds inp->coda_readlink.VFid = *fid; 3611da177e4SLinus Torvalds 362a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 3631da177e4SLinus Torvalds if (!error) { 3641da177e4SLinus Torvalds retlen = outp->coda_readlink.count; 3653725e9ddSJan Harkes if (retlen >= *length) 3663725e9ddSJan Harkes retlen = *length - 1; 3671da177e4SLinus Torvalds *length = retlen; 3681da177e4SLinus Torvalds result = (char *)outp + (long)outp->coda_readlink.data; 3691da177e4SLinus Torvalds memcpy(buffer, result, retlen); 3701da177e4SLinus Torvalds *(buffer + retlen) = '\0'; 3711da177e4SLinus Torvalds } 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds CODA_FREE(inp, insize); 3741da177e4SLinus Torvalds return error; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds int venus_link(struct super_block *sb, struct CodaFid *fid, 3801da177e4SLinus Torvalds struct CodaFid *dirfid, const char *name, int len ) 3811da177e4SLinus Torvalds { 3821da177e4SLinus Torvalds union inputArgs *inp; 3831da177e4SLinus Torvalds union outputArgs *outp; 3841da177e4SLinus Torvalds int insize, outsize, error; 3851da177e4SLinus Torvalds int offset; 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds offset = INSIZE(link); 3881da177e4SLinus Torvalds insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link)); 3891da177e4SLinus Torvalds UPARG(CODA_LINK); 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds inp->coda_link.sourceFid = *fid; 3921da177e4SLinus Torvalds inp->coda_link.destFid = *dirfid; 3931da177e4SLinus Torvalds inp->coda_link.tname = offset; 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds /* make sure strings are null terminated */ 3961da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, len); 3971da177e4SLinus Torvalds *((char *)inp + offset + len) = '\0'; 3981da177e4SLinus Torvalds 399a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds CODA_FREE(inp, insize); 4021da177e4SLinus Torvalds return error; 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds int venus_symlink(struct super_block *sb, struct CodaFid *fid, 4061da177e4SLinus Torvalds const char *name, int len, 4071da177e4SLinus Torvalds const char *symname, int symlen) 4081da177e4SLinus Torvalds { 4091da177e4SLinus Torvalds union inputArgs *inp; 4101da177e4SLinus Torvalds union outputArgs *outp; 4111da177e4SLinus Torvalds int insize, outsize, error; 4121da177e4SLinus Torvalds int offset, s; 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds offset = INSIZE(symlink); 4151da177e4SLinus Torvalds insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink)); 4161da177e4SLinus Torvalds UPARG(CODA_SYMLINK); 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds /* inp->coda_symlink.attr = *tva; XXXXXX */ 4191da177e4SLinus Torvalds inp->coda_symlink.VFid = *fid; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds /* Round up to word boundary and null terminate */ 4221da177e4SLinus Torvalds inp->coda_symlink.srcname = offset; 4231da177e4SLinus Torvalds s = ( symlen & ~0x3 ) + 4; 4241da177e4SLinus Torvalds memcpy((char *)(inp) + offset, symname, symlen); 4251da177e4SLinus Torvalds *((char *)inp + offset + symlen) = '\0'; 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds /* Round up to word boundary and null terminate */ 4281da177e4SLinus Torvalds offset += s; 4291da177e4SLinus Torvalds inp->coda_symlink.tname = offset; 4301da177e4SLinus Torvalds s = (len & ~0x3) + 4; 4311da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, len); 4321da177e4SLinus Torvalds *((char *)inp + offset + len) = '\0'; 4331da177e4SLinus Torvalds 434a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds CODA_FREE(inp, insize); 4371da177e4SLinus Torvalds return error; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds int venus_fsync(struct super_block *sb, struct CodaFid *fid) 4411da177e4SLinus Torvalds { 4421da177e4SLinus Torvalds union inputArgs *inp; 4431da177e4SLinus Torvalds union outputArgs *outp; 4441da177e4SLinus Torvalds int insize, outsize, error; 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds insize=SIZE(fsync); 4471da177e4SLinus Torvalds UPARG(CODA_FSYNC); 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds inp->coda_fsync.VFid = *fid; 450d337b66aSJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds CODA_FREE(inp, insize); 4531da177e4SLinus Torvalds return error; 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds int venus_access(struct super_block *sb, struct CodaFid *fid, int mask) 4571da177e4SLinus Torvalds { 4581da177e4SLinus Torvalds union inputArgs *inp; 4591da177e4SLinus Torvalds union outputArgs *outp; 4601da177e4SLinus Torvalds int insize, outsize, error; 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds insize = SIZE(access); 4631da177e4SLinus Torvalds UPARG(CODA_ACCESS); 4641da177e4SLinus Torvalds 4651da177e4SLinus Torvalds inp->coda_access.VFid = *fid; 4661da177e4SLinus Torvalds inp->coda_access.flags = mask; 4671da177e4SLinus Torvalds 468a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds CODA_FREE(inp, insize); 4711da177e4SLinus Torvalds return error; 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds int venus_pioctl(struct super_block *sb, struct CodaFid *fid, 4761da177e4SLinus Torvalds unsigned int cmd, struct PioctlData *data) 4771da177e4SLinus Torvalds { 4781da177e4SLinus Torvalds union inputArgs *inp; 4791da177e4SLinus Torvalds union outputArgs *outp; 4801da177e4SLinus Torvalds int insize, outsize, error; 4811da177e4SLinus Torvalds int iocsize; 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds insize = VC_MAXMSGSIZE; 4841da177e4SLinus Torvalds UPARG(CODA_IOCTL); 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds /* build packet for Venus */ 4871da177e4SLinus Torvalds if (data->vi.in_size > VC_MAXDATASIZE) { 4881da177e4SLinus Torvalds error = -EINVAL; 4891da177e4SLinus Torvalds goto exit; 4901da177e4SLinus Torvalds } 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds if (data->vi.out_size > VC_MAXDATASIZE) { 4931da177e4SLinus Torvalds error = -EINVAL; 4941da177e4SLinus Torvalds goto exit; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds inp->coda_ioctl.VFid = *fid; 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds /* the cmd field was mutated by increasing its size field to 5001da177e4SLinus Torvalds * reflect the path and follow args. We need to subtract that 5011da177e4SLinus Torvalds * out before sending the command to Venus. */ 5021da177e4SLinus Torvalds inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16)); 5031da177e4SLinus Torvalds iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int); 5041da177e4SLinus Torvalds inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16; 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds /* in->coda_ioctl.rwflag = flag; */ 5071da177e4SLinus Torvalds inp->coda_ioctl.len = data->vi.in_size; 5081da177e4SLinus Torvalds inp->coda_ioctl.data = (char *)(INSIZE(ioctl)); 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds /* get the data out of user space */ 5111da177e4SLinus Torvalds if (copy_from_user((char *)inp + (long)inp->coda_ioctl.data, 5121da177e4SLinus Torvalds data->vi.in, data->vi.in_size)) { 5131da177e4SLinus Torvalds error = -EINVAL; 5141da177e4SLinus Torvalds goto exit; 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds 517a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size, 5181da177e4SLinus Torvalds &outsize, inp); 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds if (error) { 5216d6bd94fSFabian Frederick pr_warn("%s: Venus returns: %d for %s\n", 5226d6bd94fSFabian Frederick __func__, error, coda_f2s(fid)); 5231da177e4SLinus Torvalds goto exit; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) { 5271da177e4SLinus Torvalds error = -EINVAL; 5281da177e4SLinus Torvalds goto exit; 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds /* Copy out the OUT buffer. */ 5321da177e4SLinus Torvalds if (outp->coda_ioctl.len > data->vi.out_size) { 5331da177e4SLinus Torvalds error = -EINVAL; 5341da177e4SLinus Torvalds goto exit; 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds /* Copy out the OUT buffer. */ 5381da177e4SLinus Torvalds if (copy_to_user(data->vi.out, 5391da177e4SLinus Torvalds (char *)outp + (long)outp->coda_ioctl.data, 5401da177e4SLinus Torvalds outp->coda_ioctl.len)) { 5411da177e4SLinus Torvalds error = -EFAULT; 5421da177e4SLinus Torvalds goto exit; 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds exit: 5461da177e4SLinus Torvalds CODA_FREE(inp, insize); 5471da177e4SLinus Torvalds return error; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 550726c3342SDavid Howells int venus_statfs(struct dentry *dentry, struct kstatfs *sfs) 5511da177e4SLinus Torvalds { 5521da177e4SLinus Torvalds union inputArgs *inp; 5531da177e4SLinus Torvalds union outputArgs *outp; 5541da177e4SLinus Torvalds int insize, outsize, error; 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs)); 5571da177e4SLinus Torvalds UPARG(CODA_STATFS); 5581da177e4SLinus Torvalds 559a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp); 5601da177e4SLinus Torvalds if (!error) { 5611da177e4SLinus Torvalds sfs->f_blocks = outp->coda_statfs.stat.f_blocks; 5621da177e4SLinus Torvalds sfs->f_bfree = outp->coda_statfs.stat.f_bfree; 5631da177e4SLinus Torvalds sfs->f_bavail = outp->coda_statfs.stat.f_bavail; 5641da177e4SLinus Torvalds sfs->f_files = outp->coda_statfs.stat.f_files; 5651da177e4SLinus Torvalds sfs->f_ffree = outp->coda_statfs.stat.f_ffree; 5661da177e4SLinus Torvalds } 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds CODA_FREE(inp, insize); 5691da177e4SLinus Torvalds return error; 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds /* 5731da177e4SLinus Torvalds * coda_upcall and coda_downcall routines. 5741da177e4SLinus Torvalds */ 5755f47c7eaSAl Viro static void coda_block_signals(sigset_t *old) 576d9664c95SJan Harkes { 577d9664c95SJan Harkes spin_lock_irq(¤t->sighand->siglock); 578d9664c95SJan Harkes *old = current->blocked; 5791da177e4SLinus Torvalds 580d9664c95SJan Harkes sigfillset(¤t->blocked); 581d9664c95SJan Harkes sigdelset(¤t->blocked, SIGKILL); 582d9664c95SJan Harkes sigdelset(¤t->blocked, SIGSTOP); 583d9664c95SJan Harkes sigdelset(¤t->blocked, SIGINT); 584d9664c95SJan Harkes 585d9664c95SJan Harkes recalc_sigpending(); 586d9664c95SJan Harkes spin_unlock_irq(¤t->sighand->siglock); 587d9664c95SJan Harkes } 588d9664c95SJan Harkes 5895f47c7eaSAl Viro static void coda_unblock_signals(sigset_t *old) 590d9664c95SJan Harkes { 591d9664c95SJan Harkes spin_lock_irq(¤t->sighand->siglock); 592d9664c95SJan Harkes current->blocked = *old; 593d9664c95SJan Harkes recalc_sigpending(); 594d9664c95SJan Harkes spin_unlock_irq(¤t->sighand->siglock); 595d9664c95SJan Harkes } 596d9664c95SJan Harkes 597d9664c95SJan Harkes /* Don't allow signals to interrupt the following upcalls before venus 598d9664c95SJan Harkes * has seen them, 599d9664c95SJan Harkes * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems) 600d9664c95SJan Harkes * - CODA_STORE (to avoid data loss) 601d9664c95SJan Harkes */ 602d9664c95SJan Harkes #define CODA_INTERRUPTIBLE(r) (!coda_hard && \ 603d9664c95SJan Harkes (((r)->uc_opcode != CODA_CLOSE && \ 604d9664c95SJan Harkes (r)->uc_opcode != CODA_STORE && \ 605d9664c95SJan Harkes (r)->uc_opcode != CODA_RELEASE) || \ 6064aeefdc6SJens Axboe (r)->uc_flags & CODA_REQ_READ)) 607d9664c95SJan Harkes 608da47c19eSYoshihisa Abe static inline void coda_waitfor_upcall(struct venus_comm *vcp, 609da47c19eSYoshihisa Abe struct upc_req *req) 6101da177e4SLinus Torvalds { 6111da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 612d9664c95SJan Harkes unsigned long timeout = jiffies + coda_timeout * HZ; 613d9664c95SJan Harkes sigset_t old; 614d9664c95SJan Harkes int blocked; 6151da177e4SLinus Torvalds 6165f47c7eaSAl Viro coda_block_signals(&old); 617d9664c95SJan Harkes blocked = 1; 6181da177e4SLinus Torvalds 619d9664c95SJan Harkes add_wait_queue(&req->uc_sleep, &wait); 6201da177e4SLinus Torvalds for (;;) { 621d9664c95SJan Harkes if (CODA_INTERRUPTIBLE(req)) 6221da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 6231da177e4SLinus Torvalds else 6241da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds /* got a reply */ 6274aeefdc6SJens Axboe if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT)) 6281da177e4SLinus Torvalds break; 6291da177e4SLinus Torvalds 630d9664c95SJan Harkes if (blocked && time_after(jiffies, timeout) && 631d9664c95SJan Harkes CODA_INTERRUPTIBLE(req)) 632d9664c95SJan Harkes { 6335f47c7eaSAl Viro coda_unblock_signals(&old); 634d9664c95SJan Harkes blocked = 0; 635d9664c95SJan Harkes } 636d9664c95SJan Harkes 637d9664c95SJan Harkes if (signal_pending(current)) { 638d9664c95SJan Harkes list_del(&req->uc_chain); 6391da177e4SLinus Torvalds break; 6401da177e4SLinus Torvalds } 641d9664c95SJan Harkes 642da47c19eSYoshihisa Abe mutex_unlock(&vcp->vc_mutex); 643d9664c95SJan Harkes if (blocked) 644d9664c95SJan Harkes schedule_timeout(HZ); 645d9664c95SJan Harkes else 6461da177e4SLinus Torvalds schedule(); 647da47c19eSYoshihisa Abe mutex_lock(&vcp->vc_mutex); 6481da177e4SLinus Torvalds } 649d9664c95SJan Harkes if (blocked) 6505f47c7eaSAl Viro coda_unblock_signals(&old); 6511da177e4SLinus Torvalds 652d9664c95SJan Harkes remove_wait_queue(&req->uc_sleep, &wait); 653d9664c95SJan Harkes set_current_state(TASK_RUNNING); 6541da177e4SLinus Torvalds } 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds /* 6581da177e4SLinus Torvalds * coda_upcall will return an error in the case of 6591da177e4SLinus Torvalds * failed communication with Venus _or_ will peek at Venus 6601da177e4SLinus Torvalds * reply and return Venus' error. 6611da177e4SLinus Torvalds * 6621da177e4SLinus Torvalds * As venus has 2 types of errors, normal errors (positive) and internal 6631da177e4SLinus Torvalds * errors (negative), normal errors are negated, while internal errors 6641da177e4SLinus Torvalds * are all mapped to -EINTR, while showing a nice warning message. (jh) 6651da177e4SLinus Torvalds */ 666a1b0aa87SJan Harkes static int coda_upcall(struct venus_comm *vcp, 6671da177e4SLinus Torvalds int inSize, int *outSize, 6681da177e4SLinus Torvalds union inputArgs *buffer) 6691da177e4SLinus Torvalds { 6701da177e4SLinus Torvalds union outputArgs *out; 671fe71b5f3SJan Harkes union inputArgs *sig_inputArgs; 672f7cc02b8SYoshihisa Abe struct upc_req *req = NULL, *sig_req; 673f7cc02b8SYoshihisa Abe int error; 674f7cc02b8SYoshihisa Abe 675da47c19eSYoshihisa Abe mutex_lock(&vcp->vc_mutex); 6761da177e4SLinus Torvalds 677a1b0aa87SJan Harkes if (!vcp->vc_inuse) { 678f38cfb25SFabian Frederick pr_notice("Venus dead, not sending upcall\n"); 679f7cc02b8SYoshihisa Abe error = -ENXIO; 680f7cc02b8SYoshihisa Abe goto exit; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds /* Format the request message. */ 68437461e19SJan Harkes req = kmalloc(sizeof(struct upc_req), GFP_KERNEL); 685f7cc02b8SYoshihisa Abe if (!req) { 686f7cc02b8SYoshihisa Abe error = -ENOMEM; 687f7cc02b8SYoshihisa Abe goto exit; 688f7cc02b8SYoshihisa Abe } 689fe71b5f3SJan Harkes 6901da177e4SLinus Torvalds req->uc_data = (void *)buffer; 6911da177e4SLinus Torvalds req->uc_flags = 0; 6921da177e4SLinus Torvalds req->uc_inSize = inSize; 6931da177e4SLinus Torvalds req->uc_outSize = *outSize ? *outSize : inSize; 6941da177e4SLinus Torvalds req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode; 695a1b0aa87SJan Harkes req->uc_unique = ++vcp->vc_seq; 6961da177e4SLinus Torvalds init_waitqueue_head(&req->uc_sleep); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds /* Fill in the common input args. */ 6991da177e4SLinus Torvalds ((union inputArgs *)buffer)->ih.unique = req->uc_unique; 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds /* Append msg to pending queue and poke Venus. */ 702a1b0aa87SJan Harkes list_add_tail(&req->uc_chain, &vcp->vc_pending); 7031da177e4SLinus Torvalds 704a1b0aa87SJan Harkes wake_up_interruptible(&vcp->vc_waitq); 7051da177e4SLinus Torvalds /* We can be interrupted while we wait for Venus to process 7061da177e4SLinus Torvalds * our request. If the interrupt occurs before Venus has read 7071da177e4SLinus Torvalds * the request, we dequeue and return. If it occurs after the 7081da177e4SLinus Torvalds * read but before the reply, we dequeue, send a signal 7091da177e4SLinus Torvalds * message, and return. If it occurs after the reply we ignore 7101da177e4SLinus Torvalds * it. In no case do we want to restart the syscall. If it 7111da177e4SLinus Torvalds * was interrupted by a venus shutdown (psdev_close), return 7121da177e4SLinus Torvalds * ENODEV. */ 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds /* Go to sleep. Wake up on signals only after the timeout. */ 715da47c19eSYoshihisa Abe coda_waitfor_upcall(vcp, req); 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds /* Op went through, interrupt or not... */ 7184aeefdc6SJens Axboe if (req->uc_flags & CODA_REQ_WRITE) { 7191da177e4SLinus Torvalds out = (union outputArgs *)req->uc_data; 7201da177e4SLinus Torvalds /* here we map positive Venus errors to kernel errors */ 7211da177e4SLinus Torvalds error = -out->oh.result; 7221da177e4SLinus Torvalds *outSize = req->uc_outSize; 7231da177e4SLinus Torvalds goto exit; 7241da177e4SLinus Torvalds } 725fe71b5f3SJan Harkes 7261da177e4SLinus Torvalds error = -EINTR; 7274aeefdc6SJens Axboe if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) { 728f38cfb25SFabian Frederick pr_warn("Unexpected interruption.\n"); 7291da177e4SLinus Torvalds goto exit; 7301da177e4SLinus Torvalds } 7311da177e4SLinus Torvalds 732fe71b5f3SJan Harkes /* Interrupted before venus read it. */ 7334aeefdc6SJens Axboe if (!(req->uc_flags & CODA_REQ_READ)) 734fe71b5f3SJan Harkes goto exit; 735fe71b5f3SJan Harkes 736fe71b5f3SJan Harkes /* Venus saw the upcall, make sure we can send interrupt signal */ 737a1b0aa87SJan Harkes if (!vcp->vc_inuse) { 738f38cfb25SFabian Frederick pr_info("Venus dead, not sending signal.\n"); 739fe71b5f3SJan Harkes goto exit; 740fe71b5f3SJan Harkes } 741fe71b5f3SJan Harkes 7421da177e4SLinus Torvalds error = -ENOMEM; 74337461e19SJan Harkes sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL); 7441da177e4SLinus Torvalds if (!sig_req) goto exit; 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr)); 7471da177e4SLinus Torvalds if (!sig_req->uc_data) { 74837461e19SJan Harkes kfree(sig_req); 7491da177e4SLinus Torvalds goto exit; 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds error = -EINTR; 7531da177e4SLinus Torvalds sig_inputArgs = (union inputArgs *)sig_req->uc_data; 7541da177e4SLinus Torvalds sig_inputArgs->ih.opcode = CODA_SIGNAL; 7551da177e4SLinus Torvalds sig_inputArgs->ih.unique = req->uc_unique; 7561da177e4SLinus Torvalds 7574aeefdc6SJens Axboe sig_req->uc_flags = CODA_REQ_ASYNC; 7581da177e4SLinus Torvalds sig_req->uc_opcode = sig_inputArgs->ih.opcode; 7591da177e4SLinus Torvalds sig_req->uc_unique = sig_inputArgs->ih.unique; 7601da177e4SLinus Torvalds sig_req->uc_inSize = sizeof(struct coda_in_hdr); 7611da177e4SLinus Torvalds sig_req->uc_outSize = sizeof(struct coda_in_hdr); 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds /* insert at head of queue! */ 764a1b0aa87SJan Harkes list_add(&(sig_req->uc_chain), &vcp->vc_pending); 765a1b0aa87SJan Harkes wake_up_interruptible(&vcp->vc_waitq); 7661da177e4SLinus Torvalds 7671da177e4SLinus Torvalds exit: 76837461e19SJan Harkes kfree(req); 769da47c19eSYoshihisa Abe mutex_unlock(&vcp->vc_mutex); 7701da177e4SLinus Torvalds return error; 7711da177e4SLinus Torvalds } 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds /* 7741da177e4SLinus Torvalds The statements below are part of the Coda opportunistic 7751da177e4SLinus Torvalds programming -- taken from the Mach/BSD kernel code for Coda. 7761da177e4SLinus Torvalds You don't get correct semantics by stating what needs to be 7771da177e4SLinus Torvalds done without guaranteeing the invariants needed for it to happen. 7781da177e4SLinus Torvalds When will be have time to find out what exactly is going on? (pjb) 7791da177e4SLinus Torvalds */ 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds /* 7831da177e4SLinus Torvalds * There are 7 cases where cache invalidations occur. The semantics 7841da177e4SLinus Torvalds * of each is listed here: 7851da177e4SLinus Torvalds * 7861da177e4SLinus Torvalds * CODA_FLUSH -- flush all entries from the name cache and the cnode cache. 7871da177e4SLinus Torvalds * CODA_PURGEUSER -- flush all entries from the name cache for a specific user 7881da177e4SLinus Torvalds * This call is a result of token expiration. 7891da177e4SLinus Torvalds * 7901da177e4SLinus Torvalds * The next arise as the result of callbacks on a file or directory. 7911da177e4SLinus Torvalds * CODA_ZAPFILE -- flush the cached attributes for a file. 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds * CODA_ZAPDIR -- flush the attributes for the dir and 7941da177e4SLinus Torvalds * force a new lookup for all the children 7951da177e4SLinus Torvalds of this dir. 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds * 7981da177e4SLinus Torvalds * The next is a result of Venus detecting an inconsistent file. 7991da177e4SLinus Torvalds * CODA_PURGEFID -- flush the attribute for the file 8001da177e4SLinus Torvalds * purge it and its children from the dcache 8011da177e4SLinus Torvalds * 8021da177e4SLinus Torvalds * The last allows Venus to replace local fids with global ones 8031da177e4SLinus Torvalds * during reintegration. 8041da177e4SLinus Torvalds * 8051da177e4SLinus Torvalds * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */ 8061da177e4SLinus Torvalds 8076e51f8aaSJan Harkes int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out, 8086e51f8aaSJan Harkes size_t nbytes) 8091da177e4SLinus Torvalds { 8105fd31e9aSJan Harkes struct inode *inode = NULL; 811da47c19eSYoshihisa Abe struct CodaFid *fid = NULL, *newfid; 812f7cc02b8SYoshihisa Abe struct super_block *sb; 8135fd31e9aSJan Harkes 8146e51f8aaSJan Harkes /* 8156e51f8aaSJan Harkes * Make sure we have received enough data from the cache 8166e51f8aaSJan Harkes * manager to populate the necessary fields in the buffer 8176e51f8aaSJan Harkes */ 8186e51f8aaSJan Harkes switch (opcode) { 8196e51f8aaSJan Harkes case CODA_PURGEUSER: 8206e51f8aaSJan Harkes if (nbytes < sizeof(struct coda_purgeuser_out)) 8216e51f8aaSJan Harkes return -EINVAL; 8226e51f8aaSJan Harkes break; 8236e51f8aaSJan Harkes 8246e51f8aaSJan Harkes case CODA_ZAPDIR: 8256e51f8aaSJan Harkes if (nbytes < sizeof(struct coda_zapdir_out)) 8266e51f8aaSJan Harkes return -EINVAL; 8276e51f8aaSJan Harkes break; 8286e51f8aaSJan Harkes 8296e51f8aaSJan Harkes case CODA_ZAPFILE: 8306e51f8aaSJan Harkes if (nbytes < sizeof(struct coda_zapfile_out)) 8316e51f8aaSJan Harkes return -EINVAL; 8326e51f8aaSJan Harkes break; 8336e51f8aaSJan Harkes 8346e51f8aaSJan Harkes case CODA_PURGEFID: 8356e51f8aaSJan Harkes if (nbytes < sizeof(struct coda_purgefid_out)) 8366e51f8aaSJan Harkes return -EINVAL; 8376e51f8aaSJan Harkes break; 8386e51f8aaSJan Harkes 8396e51f8aaSJan Harkes case CODA_REPLACE: 8406e51f8aaSJan Harkes if (nbytes < sizeof(struct coda_replace_out)) 8416e51f8aaSJan Harkes return -EINVAL; 8426e51f8aaSJan Harkes break; 8436e51f8aaSJan Harkes } 8446e51f8aaSJan Harkes 8451da177e4SLinus Torvalds /* Handle invalidation requests. */ 846da47c19eSYoshihisa Abe mutex_lock(&vcp->vc_mutex); 847f7cc02b8SYoshihisa Abe sb = vcp->vc_sb; 8485fd31e9aSJan Harkes if (!sb || !sb->s_root) 849f7cc02b8SYoshihisa Abe goto unlock_out; 8501da177e4SLinus Torvalds 8511da177e4SLinus Torvalds switch (opcode) { 8525fd31e9aSJan Harkes case CODA_FLUSH: 8531da177e4SLinus Torvalds coda_cache_clear_all(sb); 8541da177e4SLinus Torvalds shrink_dcache_sb(sb); 8552b0143b5SDavid Howells if (d_really_is_positive(sb->s_root)) 8562b0143b5SDavid Howells coda_flag_inode(d_inode(sb->s_root), C_FLUSH); 8575fd31e9aSJan Harkes break; 8581da177e4SLinus Torvalds 8595fd31e9aSJan Harkes case CODA_PURGEUSER: 8601da177e4SLinus Torvalds coda_cache_clear_all(sb); 8615fd31e9aSJan Harkes break; 8621da177e4SLinus Torvalds 8635fd31e9aSJan Harkes case CODA_ZAPDIR: 8645fd31e9aSJan Harkes fid = &out->coda_zapdir.CodaFid; 8655fd31e9aSJan Harkes break; 8661da177e4SLinus Torvalds 8675fd31e9aSJan Harkes case CODA_ZAPFILE: 8685fd31e9aSJan Harkes fid = &out->coda_zapfile.CodaFid; 8695fd31e9aSJan Harkes break; 8701da177e4SLinus Torvalds 8715fd31e9aSJan Harkes case CODA_PURGEFID: 8725fd31e9aSJan Harkes fid = &out->coda_purgefid.CodaFid; 873da47c19eSYoshihisa Abe break; 874da47c19eSYoshihisa Abe 875da47c19eSYoshihisa Abe case CODA_REPLACE: 876da47c19eSYoshihisa Abe fid = &out->coda_replace.OldFid; 877da47c19eSYoshihisa Abe break; 878da47c19eSYoshihisa Abe } 879da47c19eSYoshihisa Abe if (fid) 8801da177e4SLinus Torvalds inode = coda_fid_to_inode(fid, sb); 881da47c19eSYoshihisa Abe 882da47c19eSYoshihisa Abe unlock_out: 883da47c19eSYoshihisa Abe mutex_unlock(&vcp->vc_mutex); 884da47c19eSYoshihisa Abe 885da47c19eSYoshihisa Abe if (!inode) 886da47c19eSYoshihisa Abe return 0; 887da47c19eSYoshihisa Abe 888da47c19eSYoshihisa Abe switch (opcode) { 889da47c19eSYoshihisa Abe case CODA_ZAPDIR: 890da47c19eSYoshihisa Abe coda_flag_inode_children(inode, C_PURGE); 891da47c19eSYoshihisa Abe coda_flag_inode(inode, C_VATTR); 892da47c19eSYoshihisa Abe break; 893da47c19eSYoshihisa Abe 894da47c19eSYoshihisa Abe case CODA_ZAPFILE: 895da47c19eSYoshihisa Abe coda_flag_inode(inode, C_VATTR); 896da47c19eSYoshihisa Abe break; 897da47c19eSYoshihisa Abe 898da47c19eSYoshihisa Abe case CODA_PURGEFID: 8991da177e4SLinus Torvalds coda_flag_inode_children(inode, C_PURGE); 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds /* catch the dentries later if some are still busy */ 9021da177e4SLinus Torvalds coda_flag_inode(inode, C_PURGE); 9031da177e4SLinus Torvalds d_prune_aliases(inode); 9045fd31e9aSJan Harkes break; 9055fd31e9aSJan Harkes 9065fd31e9aSJan Harkes case CODA_REPLACE: 9075fd31e9aSJan Harkes newfid = &out->coda_replace.NewFid; 9085fd31e9aSJan Harkes coda_replace_fid(inode, fid, newfid); 9095fd31e9aSJan Harkes break; 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds iput(inode); 9121da177e4SLinus Torvalds return 0; 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 915