11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Mostly platform independent upcall operations to Venus: 31da177e4SLinus Torvalds * -- upcalls 41da177e4SLinus Torvalds * -- upcall routines 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Linux 2.0 version 71da177e4SLinus Torvalds * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>, 81da177e4SLinus Torvalds * Michael Callahan <callahan@maths.ox.ac.uk> 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Redone for Linux 2.1 111da177e4SLinus Torvalds * Copyright (C) 1997 Carnegie Mellon University 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * Carnegie Mellon University encourages users of this code to contribute 141da177e4SLinus Torvalds * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>. 151da177e4SLinus Torvalds */ 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include <linux/signal.h> 18e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 191da177e4SLinus Torvalds #include <linux/types.h> 201da177e4SLinus Torvalds #include <linux/kernel.h> 211da177e4SLinus Torvalds #include <linux/mm.h> 221da177e4SLinus Torvalds #include <linux/time.h> 231da177e4SLinus Torvalds #include <linux/fs.h> 241da177e4SLinus Torvalds #include <linux/file.h> 251da177e4SLinus Torvalds #include <linux/stat.h> 261da177e4SLinus Torvalds #include <linux/errno.h> 271da177e4SLinus Torvalds #include <linux/string.h> 285a0e3ad6STejun Heo #include <linux/slab.h> 29da47c19eSYoshihisa Abe #include <linux/mutex.h> 30834b46c3SFabian Frederick #include <linux/uaccess.h> 311da177e4SLinus Torvalds #include <linux/vmalloc.h> 321da177e4SLinus Torvalds #include <linux/vfs.h> 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds #include <linux/coda.h> 351da177e4SLinus Torvalds #include <linux/coda_psdev.h> 3631a203dfSAl Viro #include "coda_linux.h" 3731a203dfSAl Viro #include "coda_cache.h" 383cf01f28SJan Harkes 393cf01f28SJan Harkes #include "coda_int.h" 401da177e4SLinus Torvalds 41a1b0aa87SJan Harkes static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize, 421da177e4SLinus Torvalds union inputArgs *buffer); 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds static void *alloc_upcall(int opcode, int size) 451da177e4SLinus Torvalds { 461da177e4SLinus Torvalds union inputArgs *inp; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds CODA_ALLOC(inp, union inputArgs *, size); 491da177e4SLinus Torvalds if (!inp) 501da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds inp->ih.opcode = opcode; 539fd973e0SEric W. Biederman inp->ih.pid = task_pid_nr_ns(current, &init_pid_ns); 549fd973e0SEric W. Biederman inp->ih.pgid = task_pgrp_nr_ns(current, &init_pid_ns); 55d83f5901SEric W. Biederman inp->ih.uid = from_kuid(&init_user_ns, current_fsuid()); 56de0ca06aSAdrian Bunk 571da177e4SLinus Torvalds return (void*)inp; 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds #define UPARG(op)\ 611da177e4SLinus Torvalds do {\ 621da177e4SLinus Torvalds inp = (union inputArgs *)alloc_upcall(op, insize); \ 631da177e4SLinus Torvalds if (IS_ERR(inp)) { return PTR_ERR(inp); }\ 641da177e4SLinus Torvalds outp = (union outputArgs *)(inp); \ 651da177e4SLinus Torvalds outsize = insize; \ 661da177e4SLinus Torvalds } while (0) 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds #define INSIZE(tag) sizeof(struct coda_ ## tag ## _in) 691da177e4SLinus Torvalds #define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out) 701da177e4SLinus Torvalds #define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag)) 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds /* the upcalls */ 741da177e4SLinus Torvalds int venus_rootfid(struct super_block *sb, struct CodaFid *fidp) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds union inputArgs *inp; 771da177e4SLinus Torvalds union outputArgs *outp; 781da177e4SLinus Torvalds int insize, outsize, error; 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds insize = SIZE(root); 811da177e4SLinus Torvalds UPARG(CODA_ROOT); 821da177e4SLinus Torvalds 83a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 84970648ebSJan Harkes if (!error) 851da177e4SLinus Torvalds *fidp = outp->coda_root.VFid; 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds CODA_FREE(inp, insize); 881da177e4SLinus Torvalds return error; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds int venus_getattr(struct super_block *sb, struct CodaFid *fid, 921da177e4SLinus Torvalds struct coda_vattr *attr) 931da177e4SLinus Torvalds { 941da177e4SLinus Torvalds union inputArgs *inp; 951da177e4SLinus Torvalds union outputArgs *outp; 961da177e4SLinus Torvalds int insize, outsize, error; 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds insize = SIZE(getattr); 991da177e4SLinus Torvalds UPARG(CODA_GETATTR); 1001da177e4SLinus Torvalds inp->coda_getattr.VFid = *fid; 1011da177e4SLinus Torvalds 102a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 103970648ebSJan Harkes if (!error) 1041da177e4SLinus Torvalds *attr = outp->coda_getattr.attr; 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds CODA_FREE(inp, insize); 1071da177e4SLinus Torvalds return error; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds int venus_setattr(struct super_block *sb, struct CodaFid *fid, 1111da177e4SLinus Torvalds struct coda_vattr *vattr) 1121da177e4SLinus Torvalds { 1131da177e4SLinus Torvalds union inputArgs *inp; 1141da177e4SLinus Torvalds union outputArgs *outp; 1151da177e4SLinus Torvalds int insize, outsize, error; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds insize = SIZE(setattr); 1181da177e4SLinus Torvalds UPARG(CODA_SETATTR); 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds inp->coda_setattr.VFid = *fid; 1211da177e4SLinus Torvalds inp->coda_setattr.attr = *vattr; 1221da177e4SLinus Torvalds 123a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds CODA_FREE(inp, insize); 1261da177e4SLinus Torvalds return error; 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds int venus_lookup(struct super_block *sb, struct CodaFid *fid, 1301da177e4SLinus Torvalds const char *name, int length, int * type, 1311da177e4SLinus Torvalds struct CodaFid *resfid) 1321da177e4SLinus Torvalds { 1331da177e4SLinus Torvalds union inputArgs *inp; 1341da177e4SLinus Torvalds union outputArgs *outp; 1351da177e4SLinus Torvalds int insize, outsize, error; 1361da177e4SLinus Torvalds int offset; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds offset = INSIZE(lookup); 1391da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup)); 1401da177e4SLinus Torvalds UPARG(CODA_LOOKUP); 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds inp->coda_lookup.VFid = *fid; 1431da177e4SLinus Torvalds inp->coda_lookup.name = offset; 1441da177e4SLinus Torvalds inp->coda_lookup.flags = CLU_CASE_SENSITIVE; 1451da177e4SLinus Torvalds /* send Venus a null terminated string */ 1461da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 1471da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 1481da177e4SLinus Torvalds 149a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 150970648ebSJan Harkes if (!error) { 1511da177e4SLinus Torvalds *resfid = outp->coda_lookup.VFid; 1521da177e4SLinus Torvalds *type = outp->coda_lookup.vtype; 153970648ebSJan Harkes } 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds CODA_FREE(inp, insize); 1561da177e4SLinus Torvalds return error; 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds int venus_close(struct super_block *sb, struct CodaFid *fid, int flags, 160d83f5901SEric W. Biederman kuid_t uid) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds union inputArgs *inp; 1631da177e4SLinus Torvalds union outputArgs *outp; 1641da177e4SLinus Torvalds int insize, outsize, error; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds insize = SIZE(release); 1671da177e4SLinus Torvalds UPARG(CODA_CLOSE); 1681da177e4SLinus Torvalds 169d83f5901SEric W. Biederman inp->ih.uid = from_kuid(&init_user_ns, uid); 1701da177e4SLinus Torvalds inp->coda_close.VFid = *fid; 1711da177e4SLinus Torvalds inp->coda_close.flags = flags; 1721da177e4SLinus Torvalds 173a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds CODA_FREE(inp, insize); 1761da177e4SLinus Torvalds return error; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds int venus_open(struct super_block *sb, struct CodaFid *fid, 1801da177e4SLinus Torvalds int flags, struct file **fh) 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds union inputArgs *inp; 1831da177e4SLinus Torvalds union outputArgs *outp; 1841da177e4SLinus Torvalds int insize, outsize, error; 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds insize = SIZE(open_by_fd); 1871da177e4SLinus Torvalds UPARG(CODA_OPEN_BY_FD); 1881da177e4SLinus Torvalds 18938c2e437SJan Harkes inp->coda_open_by_fd.VFid = *fid; 19038c2e437SJan Harkes inp->coda_open_by_fd.flags = flags; 1911da177e4SLinus Torvalds 192a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 19338c2e437SJan Harkes if (!error) 1941da177e4SLinus Torvalds *fh = outp->coda_open_by_fd.fh; 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds CODA_FREE(inp, insize); 1971da177e4SLinus Torvalds return error; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, 2011da177e4SLinus Torvalds const char *name, int length, 2021da177e4SLinus Torvalds struct CodaFid *newfid, struct coda_vattr *attrs) 2031da177e4SLinus Torvalds { 2041da177e4SLinus Torvalds union inputArgs *inp; 2051da177e4SLinus Torvalds union outputArgs *outp; 2061da177e4SLinus Torvalds int insize, outsize, error; 2071da177e4SLinus Torvalds int offset; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds offset = INSIZE(mkdir); 2101da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir)); 2111da177e4SLinus Torvalds UPARG(CODA_MKDIR); 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds inp->coda_mkdir.VFid = *dirfid; 2141da177e4SLinus Torvalds inp->coda_mkdir.attr = *attrs; 2151da177e4SLinus Torvalds inp->coda_mkdir.name = offset; 2161da177e4SLinus Torvalds /* Venus must get null terminated string */ 2171da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 2181da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 2191da177e4SLinus Torvalds 220a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 221970648ebSJan Harkes if (!error) { 2221da177e4SLinus Torvalds *attrs = outp->coda_mkdir.attr; 2231da177e4SLinus Torvalds *newfid = outp->coda_mkdir.VFid; 224970648ebSJan Harkes } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds CODA_FREE(inp, insize); 2271da177e4SLinus Torvalds return error; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds int venus_rename(struct super_block *sb, struct CodaFid *old_fid, 2321da177e4SLinus Torvalds struct CodaFid *new_fid, size_t old_length, 2331da177e4SLinus Torvalds size_t new_length, const char *old_name, 2341da177e4SLinus Torvalds const char *new_name) 2351da177e4SLinus Torvalds { 2361da177e4SLinus Torvalds union inputArgs *inp; 2371da177e4SLinus Torvalds union outputArgs *outp; 2381da177e4SLinus Torvalds int insize, outsize, error; 2391da177e4SLinus Torvalds int offset, s; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds offset = INSIZE(rename); 2421da177e4SLinus Torvalds insize = max_t(unsigned int, offset + new_length + old_length + 8, 2431da177e4SLinus Torvalds OUTSIZE(rename)); 2441da177e4SLinus Torvalds UPARG(CODA_RENAME); 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds inp->coda_rename.sourceFid = *old_fid; 2471da177e4SLinus Torvalds inp->coda_rename.destFid = *new_fid; 2481da177e4SLinus Torvalds inp->coda_rename.srcname = offset; 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* Venus must receive an null terminated string */ 2511da177e4SLinus Torvalds s = ( old_length & ~0x3) +4; /* round up to word boundary */ 2521da177e4SLinus Torvalds memcpy((char *)(inp) + offset, old_name, old_length); 2531da177e4SLinus Torvalds *((char *)inp + offset + old_length) = '\0'; 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds /* another null terminated string for Venus */ 2561da177e4SLinus Torvalds offset += s; 2571da177e4SLinus Torvalds inp->coda_rename.destname = offset; 2581da177e4SLinus Torvalds s = ( new_length & ~0x3) +4; /* round up to word boundary */ 2591da177e4SLinus Torvalds memcpy((char *)(inp) + offset, new_name, new_length); 2601da177e4SLinus Torvalds *((char *)inp + offset + new_length) = '\0'; 2611da177e4SLinus Torvalds 262a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds CODA_FREE(inp, insize); 2651da177e4SLinus Torvalds return error; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds int venus_create(struct super_block *sb, struct CodaFid *dirfid, 2691da177e4SLinus Torvalds const char *name, int length, int excl, int mode, 2701da177e4SLinus Torvalds struct CodaFid *newfid, struct coda_vattr *attrs) 2711da177e4SLinus Torvalds { 2721da177e4SLinus Torvalds union inputArgs *inp; 2731da177e4SLinus Torvalds union outputArgs *outp; 2741da177e4SLinus Torvalds int insize, outsize, error; 2751da177e4SLinus Torvalds int offset; 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds offset = INSIZE(create); 2781da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create)); 2791da177e4SLinus Torvalds UPARG(CODA_CREATE); 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds inp->coda_create.VFid = *dirfid; 2821da177e4SLinus Torvalds inp->coda_create.attr.va_mode = mode; 2831da177e4SLinus Torvalds inp->coda_create.excl = excl; 2841da177e4SLinus Torvalds inp->coda_create.mode = mode; 2851da177e4SLinus Torvalds inp->coda_create.name = offset; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* Venus must get null terminated string */ 2881da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 2891da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 2901da177e4SLinus Torvalds 291a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 292970648ebSJan Harkes if (!error) { 2931da177e4SLinus Torvalds *attrs = outp->coda_create.attr; 2941da177e4SLinus Torvalds *newfid = outp->coda_create.VFid; 295970648ebSJan Harkes } 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds CODA_FREE(inp, insize); 2981da177e4SLinus Torvalds return error; 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, 3021da177e4SLinus Torvalds const char *name, int length) 3031da177e4SLinus Torvalds { 3041da177e4SLinus Torvalds union inputArgs *inp; 3051da177e4SLinus Torvalds union outputArgs *outp; 3061da177e4SLinus Torvalds int insize, outsize, error; 3071da177e4SLinus Torvalds int offset; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds offset = INSIZE(rmdir); 3101da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir)); 3111da177e4SLinus Torvalds UPARG(CODA_RMDIR); 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds inp->coda_rmdir.VFid = *dirfid; 3141da177e4SLinus Torvalds inp->coda_rmdir.name = offset; 3151da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 3161da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 3171da177e4SLinus Torvalds 318a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds CODA_FREE(inp, insize); 3211da177e4SLinus Torvalds return error; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds int venus_remove(struct super_block *sb, struct CodaFid *dirfid, 3251da177e4SLinus Torvalds const char *name, int length) 3261da177e4SLinus Torvalds { 3271da177e4SLinus Torvalds union inputArgs *inp; 3281da177e4SLinus Torvalds union outputArgs *outp; 3291da177e4SLinus Torvalds int error=0, insize, outsize, offset; 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds offset = INSIZE(remove); 3321da177e4SLinus Torvalds insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove)); 3331da177e4SLinus Torvalds UPARG(CODA_REMOVE); 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds inp->coda_remove.VFid = *dirfid; 3361da177e4SLinus Torvalds inp->coda_remove.name = offset; 3371da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, length); 3381da177e4SLinus Torvalds *((char *)inp + offset + length) = '\0'; 3391da177e4SLinus Torvalds 340a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds CODA_FREE(inp, insize); 3431da177e4SLinus Torvalds return error; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds int venus_readlink(struct super_block *sb, struct CodaFid *fid, 3471da177e4SLinus Torvalds char *buffer, int *length) 3481da177e4SLinus Torvalds { 3491da177e4SLinus Torvalds union inputArgs *inp; 3501da177e4SLinus Torvalds union outputArgs *outp; 3511da177e4SLinus Torvalds int insize, outsize, error; 3521da177e4SLinus Torvalds int retlen; 3531da177e4SLinus Torvalds char *result; 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds insize = max_t(unsigned int, 3563725e9ddSJan Harkes INSIZE(readlink), OUTSIZE(readlink)+ *length); 3571da177e4SLinus Torvalds UPARG(CODA_READLINK); 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds inp->coda_readlink.VFid = *fid; 3601da177e4SLinus Torvalds 361a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 3621da177e4SLinus Torvalds if (!error) { 3631da177e4SLinus Torvalds retlen = outp->coda_readlink.count; 3643725e9ddSJan Harkes if (retlen >= *length) 3653725e9ddSJan Harkes retlen = *length - 1; 3661da177e4SLinus Torvalds *length = retlen; 3671da177e4SLinus Torvalds result = (char *)outp + (long)outp->coda_readlink.data; 3681da177e4SLinus Torvalds memcpy(buffer, result, retlen); 3691da177e4SLinus Torvalds *(buffer + retlen) = '\0'; 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds CODA_FREE(inp, insize); 3731da177e4SLinus Torvalds return error; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds int venus_link(struct super_block *sb, struct CodaFid *fid, 3791da177e4SLinus Torvalds struct CodaFid *dirfid, const char *name, int len ) 3801da177e4SLinus Torvalds { 3811da177e4SLinus Torvalds union inputArgs *inp; 3821da177e4SLinus Torvalds union outputArgs *outp; 3831da177e4SLinus Torvalds int insize, outsize, error; 3841da177e4SLinus Torvalds int offset; 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds offset = INSIZE(link); 3871da177e4SLinus Torvalds insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link)); 3881da177e4SLinus Torvalds UPARG(CODA_LINK); 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds inp->coda_link.sourceFid = *fid; 3911da177e4SLinus Torvalds inp->coda_link.destFid = *dirfid; 3921da177e4SLinus Torvalds inp->coda_link.tname = offset; 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds /* make sure strings are null terminated */ 3951da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, len); 3961da177e4SLinus Torvalds *((char *)inp + offset + len) = '\0'; 3971da177e4SLinus Torvalds 398a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds CODA_FREE(inp, insize); 4011da177e4SLinus Torvalds return error; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds int venus_symlink(struct super_block *sb, struct CodaFid *fid, 4051da177e4SLinus Torvalds const char *name, int len, 4061da177e4SLinus Torvalds const char *symname, int symlen) 4071da177e4SLinus Torvalds { 4081da177e4SLinus Torvalds union inputArgs *inp; 4091da177e4SLinus Torvalds union outputArgs *outp; 4101da177e4SLinus Torvalds int insize, outsize, error; 4111da177e4SLinus Torvalds int offset, s; 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds offset = INSIZE(symlink); 4141da177e4SLinus Torvalds insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink)); 4151da177e4SLinus Torvalds UPARG(CODA_SYMLINK); 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds /* inp->coda_symlink.attr = *tva; XXXXXX */ 4181da177e4SLinus Torvalds inp->coda_symlink.VFid = *fid; 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds /* Round up to word boundary and null terminate */ 4211da177e4SLinus Torvalds inp->coda_symlink.srcname = offset; 4221da177e4SLinus Torvalds s = ( symlen & ~0x3 ) + 4; 4231da177e4SLinus Torvalds memcpy((char *)(inp) + offset, symname, symlen); 4241da177e4SLinus Torvalds *((char *)inp + offset + symlen) = '\0'; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds /* Round up to word boundary and null terminate */ 4271da177e4SLinus Torvalds offset += s; 4281da177e4SLinus Torvalds inp->coda_symlink.tname = offset; 4291da177e4SLinus Torvalds s = (len & ~0x3) + 4; 4301da177e4SLinus Torvalds memcpy((char *)(inp) + offset, name, len); 4311da177e4SLinus Torvalds *((char *)inp + offset + len) = '\0'; 4321da177e4SLinus Torvalds 433a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds CODA_FREE(inp, insize); 4361da177e4SLinus Torvalds return error; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds int venus_fsync(struct super_block *sb, struct CodaFid *fid) 4401da177e4SLinus Torvalds { 4411da177e4SLinus Torvalds union inputArgs *inp; 4421da177e4SLinus Torvalds union outputArgs *outp; 4431da177e4SLinus Torvalds int insize, outsize, error; 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds insize=SIZE(fsync); 4461da177e4SLinus Torvalds UPARG(CODA_FSYNC); 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds inp->coda_fsync.VFid = *fid; 449a1b0aa87SJan Harkes error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs), 4501da177e4SLinus Torvalds &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 807f7cc02b8SYoshihisa Abe int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out) 8081da177e4SLinus Torvalds { 8095fd31e9aSJan Harkes struct inode *inode = NULL; 810da47c19eSYoshihisa Abe struct CodaFid *fid = NULL, *newfid; 811f7cc02b8SYoshihisa Abe struct super_block *sb; 8125fd31e9aSJan Harkes 8131da177e4SLinus Torvalds /* Handle invalidation requests. */ 814da47c19eSYoshihisa Abe mutex_lock(&vcp->vc_mutex); 815f7cc02b8SYoshihisa Abe sb = vcp->vc_sb; 8165fd31e9aSJan Harkes if (!sb || !sb->s_root) 817f7cc02b8SYoshihisa Abe goto unlock_out; 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds switch (opcode) { 8205fd31e9aSJan Harkes case CODA_FLUSH: 8211da177e4SLinus Torvalds coda_cache_clear_all(sb); 8221da177e4SLinus Torvalds shrink_dcache_sb(sb); 8232b0143b5SDavid Howells if (d_really_is_positive(sb->s_root)) 8242b0143b5SDavid Howells coda_flag_inode(d_inode(sb->s_root), C_FLUSH); 8255fd31e9aSJan Harkes break; 8261da177e4SLinus Torvalds 8275fd31e9aSJan Harkes case CODA_PURGEUSER: 8281da177e4SLinus Torvalds coda_cache_clear_all(sb); 8295fd31e9aSJan Harkes break; 8301da177e4SLinus Torvalds 8315fd31e9aSJan Harkes case CODA_ZAPDIR: 8325fd31e9aSJan Harkes fid = &out->coda_zapdir.CodaFid; 8335fd31e9aSJan Harkes break; 8341da177e4SLinus Torvalds 8355fd31e9aSJan Harkes case CODA_ZAPFILE: 8365fd31e9aSJan Harkes fid = &out->coda_zapfile.CodaFid; 8375fd31e9aSJan Harkes break; 8381da177e4SLinus Torvalds 8395fd31e9aSJan Harkes case CODA_PURGEFID: 8405fd31e9aSJan Harkes fid = &out->coda_purgefid.CodaFid; 841da47c19eSYoshihisa Abe break; 842da47c19eSYoshihisa Abe 843da47c19eSYoshihisa Abe case CODA_REPLACE: 844da47c19eSYoshihisa Abe fid = &out->coda_replace.OldFid; 845da47c19eSYoshihisa Abe break; 846da47c19eSYoshihisa Abe } 847da47c19eSYoshihisa Abe if (fid) 8481da177e4SLinus Torvalds inode = coda_fid_to_inode(fid, sb); 849da47c19eSYoshihisa Abe 850da47c19eSYoshihisa Abe unlock_out: 851da47c19eSYoshihisa Abe mutex_unlock(&vcp->vc_mutex); 852da47c19eSYoshihisa Abe 853da47c19eSYoshihisa Abe if (!inode) 854da47c19eSYoshihisa Abe return 0; 855da47c19eSYoshihisa Abe 856da47c19eSYoshihisa Abe switch (opcode) { 857da47c19eSYoshihisa Abe case CODA_ZAPDIR: 858da47c19eSYoshihisa Abe coda_flag_inode_children(inode, C_PURGE); 859da47c19eSYoshihisa Abe coda_flag_inode(inode, C_VATTR); 860da47c19eSYoshihisa Abe break; 861da47c19eSYoshihisa Abe 862da47c19eSYoshihisa Abe case CODA_ZAPFILE: 863da47c19eSYoshihisa Abe coda_flag_inode(inode, C_VATTR); 864da47c19eSYoshihisa Abe break; 865da47c19eSYoshihisa Abe 866da47c19eSYoshihisa Abe case CODA_PURGEFID: 8671da177e4SLinus Torvalds coda_flag_inode_children(inode, C_PURGE); 8681da177e4SLinus Torvalds 8691da177e4SLinus Torvalds /* catch the dentries later if some are still busy */ 8701da177e4SLinus Torvalds coda_flag_inode(inode, C_PURGE); 8711da177e4SLinus Torvalds d_prune_aliases(inode); 8725fd31e9aSJan Harkes break; 8735fd31e9aSJan Harkes 8745fd31e9aSJan Harkes case CODA_REPLACE: 8755fd31e9aSJan Harkes newfid = &out->coda_replace.NewFid; 8765fd31e9aSJan Harkes coda_replace_fid(inode, fid, newfid); 8775fd31e9aSJan Harkes break; 8781da177e4SLinus Torvalds } 8791da177e4SLinus Torvalds iput(inode); 8801da177e4SLinus Torvalds return 0; 8811da177e4SLinus Torvalds } 8821da177e4SLinus Torvalds 883