2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include "../afs/param.h"
15 #include "../afs/sysincludes.h" /* Standard vendor system headers */
16 #include "../afs/afsincludes.h" /* Afs-based standard headers */
17 #include "../afs/afs_stats.h" /* afs statistics */
18 #include "../afs/vice.h"
19 #include "../rx/rx_globals.h"
21 extern void afs_ComputePAGStats();
22 extern struct vcache *afs_LookupVCache();
23 struct VenusFid afs_rootFid;
24 afs_int32 afs_waitForever=0;
25 short afs_waitForeverCount = 0;
26 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
27 extern afs_int32 PROBE_INTERVAL;
29 extern int cacheDiskType;
30 extern afs_int32 afs_cacheBlocks;
31 extern struct afs_q CellLRU;
32 extern char *afs_indexFlags; /* only one: is there data there? */
33 extern afs_int32 afs_blocksUsed;
34 extern struct unixuser *afs_users[NUSERS];
35 extern struct server *afs_servers[NSERVERS];
36 extern struct interfaceAddr afs_cb_interface; /* client interface addresses */
37 extern afs_rwlock_t afs_xserver;
38 extern afs_rwlock_t afs_xinterface;
39 extern afs_rwlock_t afs_xcell;
40 extern afs_rwlock_t afs_xuser;
41 #ifndef AFS_FINEG_SUNLOCK
42 extern afs_rwlock_t afs_xconn;
44 extern afs_rwlock_t afs_xvolume;
45 extern afs_lock_t afs_xdcache; /* lock: alloc new disk cache entries */
46 extern afs_rwlock_t afs_xvcache;
47 extern afs_rwlock_t afs_xcbhash;
48 extern afs_int32 afs_mariner, afs_marinerHost;
49 extern struct srvAddr *afs_srvAddrs[NSERVERS];
50 extern int afs_resourceinit_flag;
51 extern afs_int32 cryptall;
53 static int PBogus(), PSetAcl(), PGetAcl(), PSetTokens(), PGetVolumeStatus();
54 static int PSetVolumeStatus(), PFlush(), PNewStatMount(), PGetTokens(), PUnlog();
55 static int PCheckServers(), PCheckVolNames(), PCheckAuth(), PFindVolume();
56 static int PViceAccess(), PSetCacheSize(), Prefetch();
57 static int PRemoveCallBack(), PNewCell(), PListCells(), PRemoveMount();
58 static int PMariner(), PGetUserCell(), PGetWSCell(), PGetFileCell();
59 static int PVenusLogging(), PNoop(), PSetCellStatus(), PGetCellStatus();
60 static int PFlushVolumeData(), PGetCacheSize();
61 static int PSetSysName(),PGetFID();
62 static int PGetVnodeXStatus();
63 static int PSetSPrefs(), PGetSPrefs(), PGag(), PTwiddleRx();
64 static int PSetSPrefs33(), PStoreBehind(), PGCPAGs();
65 static int PGetCPrefs(), PSetCPrefs(); /* client network addresses */
66 static int PGetInitParams(), PFlushMount(), PRxStatProc(), PRxStatPeer();
67 static int PGetRxkcrypt(), PSetRxkcrypt();
68 static int PPrefetchFromTape(), PResidencyCmd();
69 static int PNewAlias(), PListAliases();
72 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp);
74 extern struct cm_initparams cm_initParams;
76 static int (*(VpioctlSw[]))() = {
81 PGetVolumeStatus, /* 4 */
82 PSetVolumeStatus, /* 5 */
87 PCheckServers, /* 10 */
88 PCheckVolNames, /* 11 */
90 PBogus, /* 13 -- used to be quick check time */
92 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
93 PBogus, /* 16 -- used to be testing code */
94 PNoop, /* 17 -- used to be enable group */
95 PNoop, /* 18 -- used to be disable group */
96 PBogus, /* 19 -- used to be list group */
98 PUnlog, /* 21 -- unlog *is* unpag in this system */
99 PGetFID, /* 22 -- get file ID */
100 PBogus, /* 23 -- used to be waitforever */
101 PSetCacheSize, /* 24 */
102 PRemoveCallBack, /* 25 -- flush only the callback */
105 PRemoveMount, /* 28 -- delete mount point */
106 PNewStatMount, /* 29 -- new style mount point stat */
107 PGetFileCell, /* 30 -- get cell name for input file */
108 PGetWSCell, /* 31 -- get cell name for workstation */
109 PMariner, /* 32 - set/get mariner host */
110 PGetUserCell, /* 33 -- get cell name for user */
111 PVenusLogging, /* 34 -- Enable/Disable logging */
112 PGetCellStatus, /* 35 */
113 PSetCellStatus, /* 36 */
114 PFlushVolumeData, /* 37 -- flush all data from a volume */
115 PSetSysName, /* 38 - Set system name */
116 PExportAfs, /* 39 - Export Afs to remote nfs clients */
117 PGetCacheSize, /* 40 - get cache size and usage */
118 PGetVnodeXStatus, /* 41 - get vcache's special status */
119 PSetSPrefs33, /* 42 - Set CM Server preferences... */
120 PGetSPrefs, /* 43 - Get CM Server preferences... */
121 PGag, /* 44 - turn off/on all CM messages */
122 PTwiddleRx, /* 45 - adjust some RX params */
123 PSetSPrefs, /* 46 - Set CM Server preferences... */
124 PStoreBehind, /* 47 - set degree of store behind to be done */
125 PGCPAGs, /* 48 - disable automatic pag gc-ing */
126 PGetInitParams, /* 49 - get initial cm params */
127 PGetCPrefs, /* 50 - get client interface addresses */
128 PSetCPrefs, /* 51 - set client interface addresses */
129 PFlushMount, /* 52 - flush mount symlink data */
130 PRxStatProc, /* 53 - control process RX statistics */
131 PRxStatPeer, /* 54 - control peer RX statistics */
132 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
133 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
134 PNoop, /* 57 -- arla: set file prio */
135 PNoop, /* 58 -- arla: fallback getfh */
136 PNoop, /* 59 -- arla: fallback fhopen */
137 PNoop, /* 60 -- arla: controls xfsdebug */
138 PNoop, /* 61 -- arla: controls arla debug */
139 PNoop, /* 62 -- arla: debug interface */
140 PNoop, /* 63 -- arla: print xfs status */
141 PNoop, /* 64 -- arla: force cache check */
142 PNoop, /* 65 -- arla: break callback */
143 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
144 PResidencyCmd, /* 67 -- MR-AFS: generic commnd interface */
145 PNoop, /* 68 -- arla: fetch stats */
148 static int (*(CpioctlSw[]))() = {
150 PNewAlias, /* 1 -- create new cell alias */
151 PListAliases, /* 2 -- list cell aliases */
154 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
155 int afs_nobody = NFS_NOBODY;
158 afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst)
160 dst->in = (char *)(unsigned long)src->in;
161 dst->out = (char *)(unsigned long)src->out;
162 dst->in_size = src->in_size;
163 dst->out_size = src->out_size;
167 * If you need to change copyin_afs_ioctl(), you may also need to change
172 copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
176 #if defined(AFS_HPUX_64BIT_ENV)
177 struct afs_ioctl32 dst32;
179 if (is_32bit(u.u_procp)) /* is_32bit() in proc_iface.h */
181 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
183 afs_ioctl32_to_afs_ioctl(&dst32, dst);
186 #endif /* defined(AFS_HPUX_64BIT_ENV) */
188 #if defined(AFS_SUN57_64BIT_ENV)
189 struct afs_ioctl32 dst32;
191 if (get_udatamodel() == DATAMODEL_ILP32) {
192 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
194 afs_ioctl32_to_afs_ioctl(&dst32, dst);
197 #endif /* defined(AFS_SUN57_64BIT_ENV) */
199 #if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)
200 struct afs_ioctl32 dst32;
202 if (!ABI_IS_64BIT(get_current_abi()))
204 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
206 afs_ioctl32_to_afs_ioctl(&dst32, dst);
209 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
211 #if defined(AFS_LINUX_64BIT_KERNEL) && !defined(AFS_ALPHA_LINUX20_ENV) && !defined(AFS_IA64_LINUX20_ENV)
212 struct afs_ioctl32 dst32;
214 #ifdef AFS_SPARC64_LINUX24_ENV
215 if (current->thread.flags & SPARC_FLAG_32BIT)
216 #elif AFS_SPARC64_LINUX20_ENV
217 if (current->tss.flags & SPARC_FLAG_32BIT)
219 #error Not done for this linux type
220 #endif /* AFS_SPARC64_LINUX20_ENV */
222 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
224 afs_ioctl32_to_afs_ioctl(&dst32, dst);
227 #endif /* defined(AFS_LINUX_64BIT_KERNEL) */
229 AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
233 HandleIoctl(avc, acom, adata)
234 register struct vcache *avc;
235 register afs_int32 acom;
236 struct afs_ioctl *adata; {
237 register afs_int32 code;
240 AFS_STATCNT(HandleIoctl);
242 switch(acom & 0xff) {
244 avc->states |= CSafeStore;
248 /* case 2 used to be abort store, but this is no longer provided,
249 since it is impossible to implement under normal Unix.
253 /* return the name of the cell this file is open on */
254 register struct cell *tcell;
255 register afs_int32 i;
257 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
259 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
261 if (i > adata->out_size) {
262 /* 0 means we're not interested in the output */
263 if (adata->out_size != 0) code = EFAULT;
267 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
269 afs_PutCell(tcell, READ_LOCK);
275 case 49: /* VIOC_GETINITPARAMS */
276 if (adata->out_size < sizeof(struct cm_initparams)) {
280 AFS_COPYOUT(&cm_initParams, adata->out,
281 sizeof(struct cm_initparams), code);
290 return code; /* so far, none implemented */
295 /* For aix we don't temporarily bypass ioctl(2) but rather do our
296 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
297 * is now called from afs_gn_ioctl.
299 afs_ioctl(tvc, cmd, arg)
304 struct afs_ioctl data;
307 AFS_STATCNT(afs_ioctl);
308 if (((cmd >> 8) & 0xff) == 'V') {
309 /* This is a VICEIOCTL call */
310 AFS_COPYIN(arg, (caddr_t) &data, sizeof(data), error);
313 error = HandleIoctl(tvc, cmd, &data);
316 /* No-op call; just return. */
320 #endif /* AFS_AIX_ENV */
322 #if defined(AFS_SGI_ENV)
323 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void * arg, int flag, cred_t *cr, rval_t *rvalp
329 struct afs_ioctl data;
335 AFS_STATCNT(afs_ioctl);
336 if (((cmd >> 8) & 0xff) == 'V') {
337 /* This is a VICEIOCTL call */
338 error = copyin_afs_ioctl(arg, &data);
341 locked = ISAFS_GLOCK();
344 error = HandleIoctl(tvc, cmd, &data);
349 /* No-op call; just return. */
353 #endif /* AFS_SGI_ENV */
356 /* unlike most calls here, this one uses u.u_error to return error conditions,
357 since this is really an intercepted chapter 2 call, rather than a vnode
360 /* AFS_HPUX102 and up uses VNODE ioctl instead */
361 #ifndef AFS_HPUX102_ENV
362 #if !defined(AFS_SGI_ENV)
364 kioctl(fdes, com, arg, ext)
371 } u_uap, *uap = &u_uap;
375 struct afs_ioctl_sys {
381 afs_xioctl (uap, rvp)
382 struct afs_ioctl_sys *uap;
387 afs_xioctl (p, args, retval)
396 } *uap = (struct a *)args;
397 #else /* AFS_OSF_ENV */
398 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
404 afs_xioctl(p, uap, retval)
406 register struct ioctl_args *uap;
410 #ifdef AFS_LINUX22_ENV
411 struct afs_ioctl_sys {
415 asmlinkage int afs_xioctl(struct inode *ip, struct file *fp,
416 unsigned int com, unsigned long arg)
418 struct afs_ioctl_sys ua, *uap = &ua;
426 } *uap = (struct a *)u.u_ap;
427 #endif /* AFS_LINUX22_ENV */
428 #endif /* AFS_DARWIN_ENV || AFS_FBSD_ENV */
429 #endif /* AFS_OSF_ENV */
430 #endif /* AFS_SUN5_ENV */
432 #ifndef AFS_LINUX22_ENV
433 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
436 register struct file *fd;
439 register struct vcache *tvc;
440 register int ioctlDone = 0, code = 0;
442 AFS_STATCNT(afs_xioctl);
443 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
444 if ((code=fdgetf(p, uap->fd, &fd)))
447 #ifdef AFS_LINUX22_ENV
455 if (setuerror(getf(uap->fd, &fd))) {
461 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
463 #else /* AFS_OSF_ENV */
465 #if defined(AFS_SUN57_ENV)
467 if (!fd) return(EBADF);
468 #elif defined(AFS_SUN54_ENV)
470 if (!fd) return(EBADF);
472 if (code = getf(uap->fd, &fd)) {
485 /* first determine whether this is any sort of vnode */
486 #ifdef AFS_LINUX22_ENV
487 tvc = (struct vcache *)ip;
491 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
493 if (fd->f_type == DTYPE_VNODE) {
495 /* good, this is a vnode; next see if it is an AFS vnode */
496 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
497 tvc = (struct vcache *) fd->f_vnode; /* valid, given a vnode */
499 tvc = (struct vcache *) fd->f_data; /* valid, given a vnode */
501 #endif /* AFS_LINUX22_ENV */
502 if (tvc && IsAfsVnode((struct vnode *)tvc)) {
504 tvc = (struct vcache *) afs_gntovn((struct gnode *) tvc);
505 if (!tvc) { /* shouldn't happen with held gnodes */
510 /* This is an AFS vnode */
511 if (((uap->com >> 8) & 0xff) == 'V') {
512 register struct afs_ioctl *datap;
514 datap = (struct afs_ioctl *) osi_AllocSmallSpace(AFS_SMALLOCSIZ);
515 AFS_COPYIN((char *)uap->arg, (caddr_t) datap, sizeof (struct afs_ioctl), code);
517 osi_FreeSmallSpace(datap);
519 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
522 #if defined(AFS_SUN5_ENV)
537 #else /* AFS_OSF_ENV */
541 #ifdef AFS_LINUX22_ENV
551 code = HandleIoctl(tvc, uap->com, datap);
552 osi_FreeSmallSpace(datap);
566 #if defined(AFS_LINUX22_ENV)
576 code = okioctl(fdes, com, arg, ext);
580 okioctl(fdes, com, arg, ext);
582 #if defined(AFS_SUN5_ENV)
583 #if defined(AFS_SUN57_ENV)
585 #elif defined(AFS_SUN54_ENV)
590 code = ioctl(uap, rvp);
592 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
593 return ioctl(p, uap, retval);
596 code = ioctl(p, args, retval);
603 #else /* AFS_OSF_ENV */
604 #ifndef AFS_LINUX22_ENV
622 #ifdef AFS_LINUX22_ENV
625 #if !defined(AFS_OSF_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
628 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
629 return (getuerror() ? -1 : u.u_ioctlrv);
631 return getuerror() ? -1 : 0;
634 #endif /* AFS_LINUX22_ENV */
635 #endif /* AFS_SUN5_ENV */
636 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
640 #endif /* AFS_SGI_ENV */
641 #endif /* AFS_HPUX102_ENV */
643 #if defined(AFS_SGI_ENV)
644 /* "pioctl" system call entry point; just pass argument to the parameterized
653 afs_pioctl(struct pioctlargs *uap, rval_t *rvp)
657 AFS_STATCNT(afs_pioctl);
659 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
667 #endif /* AFS_SGI_ENV */
670 afs_pioctl(p, args, retval)
680 } *uap = (struct a *) args;
682 AFS_STATCNT(afs_pioctl);
683 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
686 extern struct mount *afs_globalVFS;
687 #else /* AFS_OSF_ENV */
688 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
689 afs_pioctl(p, args, retval)
699 } *uap = (struct a *) args;
701 AFS_STATCNT(afs_pioctl);
702 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow, p->p_cred->pc_ucred));
705 extern struct mount *afs_globalVFS;
706 #else /* AFS_OSF_ENV */
707 extern struct vfs *afs_globalVFS;
711 /* macro to avoid adding any more #ifdef's to pioctl code. */
712 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
713 #define PIOCTL_FREE_CRED() crfree(credp)
715 #define PIOCTL_FREE_CRED()
719 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
721 struct AFS_UCRED *credp;
723 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
724 afs_syscall_pioctl(path, com, cmarg, follow, credp)
725 struct AFS_UCRED *credp;
727 afs_syscall_pioctl(path, com, cmarg, follow)
735 struct afs_ioctl data;
736 struct AFS_UCRED *tmpcred, *foreigncreds = 0;
737 register afs_int32 code = 0;
743 struct ucred *credp = crref(); /* don't free until done! */
745 #ifdef AFS_LINUX22_ENV
746 cred_t *credp = crref(); /* don't free until done! */
750 AFS_STATCNT(afs_syscall_pioctl);
751 if (follow) follow = 1; /* compat. with old venus */
752 code = copyin_afs_ioctl(cmarg, &data);
755 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
762 if ((com & 0xff) == PSetClientContext) {
763 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
764 return EINVAL; /* Not handling these yet. */
766 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
767 code = HandleClientContext(&data, &com, &foreigncreds, credp);
769 #if defined(AFS_HPUX101_ENV)
770 code=HandleClientContext(&data, &com, &foreigncreds, p_cred(u.u_procp));
773 code = HandleClientContext(&data, &com, &foreigncreds, OSI_GET_CURRENT_CRED());
775 code = HandleClientContext(&data, &com, &foreigncreds, u.u_cred);
776 #endif /* AFS_SGI_ENV */
782 crfree(foreigncreds);
785 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
788 return (setuerror(code), code);
792 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
795 * We could have done without temporary setting the u.u_cred below
796 * (foreigncreds could be passed as param the pioctl modules)
797 * but calls such as afs_osi_suser() doesn't allow that since it
798 * references u.u_cred directly. We could, of course, do something
799 * like afs_osi_suser(cred) which, I think, is better since it
800 * generalizes and supports multi cred environments...
804 credp = foreigncreds;
807 tmpcred = crref(); /* XXX */
810 #if defined(AFS_HPUX101_ENV)
811 tmpcred = p_cred(u.u_procp);
812 set_p_cred(u.u_procp, foreigncreds);
815 tmpcred = OSI_GET_CURRENT_CRED();
816 OSI_SET_CURRENT_CRED(foreigncreds);
819 u.u_cred = foreigncreds;
820 #endif /* AFS_SGI64_ENV */
821 #endif /* AFS_HPUX101_ENV */
826 if ((com & 0xff) == 15) {
827 /* special case prefetch so entire pathname eval occurs in helper process.
828 otherwise, the pioctl call is essentially useless */
829 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
830 code = Prefetch(path, &data, follow,
831 foreigncreds ? foreigncreds : credp);
833 #if defined(AFS_HPUX101_ENV)
834 code = Prefetch(path, &data, follow, p_cred(u.u_procp));
837 code = Prefetch(path, &data, follow, OSI_GET_CURRENT_CRED());
839 code = Prefetch(path, &data, follow, u.u_cred);
840 #endif /* AFS_SGI64_ENV */
841 #endif /* AFS_HPUX101_ENV */
843 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
846 crset(tmpcred); /* restore original credentials */
848 #if defined(AFS_HPUX101_ENV)
849 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
853 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
855 u.u_cred = tmpcred; /* restore original credentials */
858 #endif /* AFS_HPUX101_ENV */
859 crfree(foreigncreds);
862 #endif /* AFS_LINUX22_ENV */
864 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
867 return (setuerror(code), code);
873 code = lookupname(path, USR, follow, NULL, &vp,
874 foreigncreds ? foreigncreds : credp);
876 #ifdef AFS_LINUX22_ENV
877 code = gop_lookupname(path, AFS_UIOUSER, follow, (struct vnode **) 0, &dp);
879 vp = (struct vnode *)dp->d_inode;
881 code = gop_lookupname(path, AFS_UIOUSER, follow, (struct vnode **) 0, &vp);
882 #endif /* AFS_LINUX22_ENV */
883 #endif /* AFS_AIX41_ENV */
886 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
889 crset(tmpcred); /* restore original credentials */
891 #if defined(AFS_HPUX101_ENV)
892 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
894 #if !defined(AFS_SUN5_ENV)
896 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
898 u.u_cred = tmpcred; /* restore original credentials */
899 #endif /* AFS_SGI64_ENV */
901 #endif /* AFS_HPUX101_ENV */
902 crfree(foreigncreds);
905 #endif /* AFS_LINUX22_ENV */
907 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
910 return(setuerror(code), code);
914 else vp = (struct vnode *) 0;
916 /* now make the call if we were passed no file, or were passed an AFS file */
917 if (!vp || IsAfsVnode(vp)) {
919 /* Ultrix 4.0: can't get vcache entry unless we've got an AFS gnode.
920 * So, we must test in this part of the code. Also, must arrange to
921 * GRELE the original gnode pointer when we're done, since in Ultrix 4.0,
922 * we hold gnodes, whose references hold our vcache entries.
925 gp = vp; /* remember for "put" */
926 vp = (struct vnode *) afs_gntovn(vp); /* get vcache from gp */
928 else gp = (struct vnode *) 0;
931 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
935 struct ucred *cred1, *cred2;
938 cred1 = cred2 = foreigncreds;
940 cred1 = cred2 = credp;
942 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
943 if (cred1 != cred2) {
944 /* something changed the creds */
949 #if defined(AFS_HPUX101_ENV)
951 struct ucred *cred = p_cred(u.u_procp);
952 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
958 credp = OSI_GET_CURRENT_CRED();
959 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
962 #if defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
963 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
965 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
967 #endif /* AFS_SGI_ENV */
968 #endif /* AFS_HPUX101_ENV */
969 #endif /* AFS_AIX41_ENV */
970 #endif /* AFS_SUN5_ENV */
972 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
973 code = EINVAL; /* not in /afs */
980 vp = (struct vnode *) 0;
985 #if !defined(AFS_LINUX22_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
990 #if defined(AFS_HPUX101_ENV)
991 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
995 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
997 u.u_cred = tmpcred; /* restore original credentials */
998 #endif /* ASF_SGI64_ENV */
1000 #endif /* AFS_HPUX101_ENV */
1001 crfree(foreigncreds);
1004 #endif /* AFS_LINUX22_ENV */
1006 #ifdef AFS_LINUX22_ENV
1009 AFS_RELE(vp); /* put vnode back */
1013 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1018 return (getuerror());
1023 afs_HandlePioctl(avc, acom, ablob, afollow, acred)
1024 register struct vcache *avc;
1026 struct AFS_UCRED **acred;
1027 register struct afs_ioctl *ablob;
1030 struct vrequest treq;
1031 register afs_int32 code;
1032 register afs_int32 function, device;
1033 afs_int32 inSize, outSize;
1034 char *inData, *outData;
1035 int (*(*pioctlSw))();
1038 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1039 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1040 AFS_STATCNT(HandlePioctl);
1041 if (code = afs_InitReq(&treq, *acred)) return code;
1042 device = (acom & 0xff00) >> 8;
1044 case 'V': /* Original pioctl's */
1045 pioctlSw = VpioctlSw;
1046 pioctlSwSize = sizeof(VpioctlSw);
1048 case 'C': /* Coordinated/common pioctl's */
1049 pioctlSw = CpioctlSw;
1050 pioctlSwSize = sizeof(CpioctlSw);
1055 function = acom & 0xff;
1056 if (function >= (pioctlSwSize / sizeof(char *))) {
1057 return EINVAL; /* out of range */
1059 inSize = ablob->in_size;
1060 if (inSize >= PIGGYSIZE) return E2BIG;
1061 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1063 AFS_COPYIN(ablob->in, inData, inSize, code);
1067 osi_FreeLargeSpace(inData);
1070 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1072 if (function == 3 && device == 'V') /* PSetTokens */
1073 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
1075 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, *acred);
1076 osi_FreeLargeSpace(inData);
1077 if (code == 0 && ablob->out_size > 0) {
1078 if (outSize > ablob->out_size) outSize = ablob->out_size;
1079 if (outSize >= PIGGYSIZE) code = E2BIG;
1081 AFS_COPYOUT(outData, ablob->out, outSize, code);
1083 osi_FreeLargeSpace(outData);
1084 return afs_CheckCode(code, &treq, 41);
1087 static PGetFID(avc, afun, areq, ain, aout, ainSize, aoutSize)
1090 struct vrequest *areq;
1093 afs_int32 *aoutSize; /* set this */ {
1094 register afs_int32 code;
1096 AFS_STATCNT(PGetFID);
1097 if (!avc) return EINVAL;
1098 memcpy(aout, (char *)&avc->fid, sizeof(struct VenusFid));
1099 *aoutSize = sizeof(struct VenusFid);
1103 static PSetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1106 struct vrequest *areq;
1109 afs_int32 *aoutSize; /* set this */ {
1110 register afs_int32 code;
1112 struct AFSOpaque acl;
1113 struct AFSVolSync tsync;
1114 struct AFSFetchStatus OutStatus;
1117 AFS_STATCNT(PSetAcl);
1120 if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1123 acl.AFSOpaque_val = ain;
1125 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1127 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1128 #ifdef RX_ENABLE_LOCKS
1130 #endif /* RX_ENABLE_LOCKS */
1131 code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1132 &acl, &OutStatus, &tsync);
1133 #ifdef RX_ENABLE_LOCKS
1135 #endif /* RX_ENABLE_LOCKS */
1140 (afs_Analyze(tconn, code, &avc->fid, areq,
1141 AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, (struct cell *)0));
1143 /* now we've forgotten all of the access info */
1144 ObtainWriteLock(&afs_xcbhash, 455);
1146 afs_DequeueCallback(avc);
1147 avc->states &= ~(CStatd | CUnique);
1148 ReleaseWriteLock(&afs_xcbhash);
1149 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1150 osi_dnlc_purgedp(avc);
1154 int afs_defaultAsynchrony = 0;
1156 static PStoreBehind(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1159 struct vrequest *areq;
1162 afs_int32 *aoutSize; /* set this */
1163 struct AFS_UCRED *acred;
1166 struct sbstruct *sbr;
1168 sbr = (struct sbstruct *)ain;
1169 if (sbr->sb_default != -1) {
1170 if (afs_osi_suser(acred))
1171 afs_defaultAsynchrony = sbr->sb_default;
1175 if (avc && (sbr->sb_thisfile != -1))
1176 if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER,
1177 areq, DONT_CHECK_MODE_BITS))
1178 avc->asynchrony = sbr->sb_thisfile;
1181 *aoutSize = sizeof(struct sbstruct);
1182 sbr = (struct sbstruct *)aout;
1183 sbr->sb_default = afs_defaultAsynchrony;
1185 sbr->sb_thisfile = avc->asynchrony;
1191 static PGCPAGs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1194 struct vrequest *areq;
1197 afs_int32 *aoutSize; /* set this */
1198 struct AFS_UCRED *acred;
1200 if (!afs_osi_suser(acred)) {
1203 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1207 static PGetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1210 struct vrequest *areq;
1213 afs_int32 *aoutSize; /* set this */ {
1214 struct AFSOpaque acl;
1215 struct AFSVolSync tsync;
1216 struct AFSFetchStatus OutStatus;
1222 AFS_STATCNT(PGetAcl);
1223 if (!avc) return EINVAL;
1224 Fid.Volume = avc->fid.Fid.Volume;
1225 Fid.Vnode = avc->fid.Fid.Vnode;
1226 Fid.Unique = avc->fid.Fid.Unique;
1227 if (avc->states & CForeign) {
1229 * For a dfs xlator acl we have a special hack so that the
1230 * xlator will distinguish which type of acl will return. So
1231 * we currently use the top 2-bytes (vals 0-4) to tell which
1232 * type of acl to bring back. Horrible hack but this will
1233 * cause the least number of changes to code size and interfaces.
1235 if (Fid.Vnode & 0xc0000000)
1237 Fid.Vnode |= (ainSize << 30);
1239 acl.AFSOpaque_val = aout;
1241 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1244 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1245 #ifdef RX_ENABLE_LOCKS
1247 #endif /* RX_ENABLE_LOCKS */
1248 code = RXAFS_FetchACL(tconn->id, &Fid,
1249 &acl, &OutStatus, &tsync);
1250 #ifdef RX_ENABLE_LOCKS
1252 #endif /* RX_ENABLE_LOCKS */
1257 (afs_Analyze(tconn, code, &avc->fid, areq,
1258 AFS_STATS_FS_RPCIDX_FETCHACL,
1259 SHARED_LOCK, (struct cell *)0));
1262 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1273 AFS_STATCNT(PBogus);
1277 static PGetFileCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1280 struct vrequest *areq;
1284 afs_int32 *aoutSize; /* set this */ {
1285 register struct cell *tcell;
1287 AFS_STATCNT(PGetFileCell);
1288 if (!avc) return EINVAL;
1289 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1290 if (!tcell) return ESRCH;
1291 strcpy(aout, tcell->cellName);
1292 afs_PutCell(tcell, READ_LOCK);
1293 *aoutSize = strlen(aout) + 1;
1297 static PGetWSCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1300 struct vrequest *areq;
1304 afs_int32 *aoutSize; /* set this */ {
1305 register struct cell *tcell=0, *cellOne=0;
1306 register struct afs_q *cq, *tq;
1308 AFS_STATCNT(PGetWSCell);
1309 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1310 return EIO; /* Inappropriate ioctl for device */
1312 ObtainReadLock(&afs_xcell);
1313 cellOne = (struct cell *) 0;
1315 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
1316 tcell = QTOC(cq); tq = QNext(cq);
1317 if (tcell->states & CPrimary) break;
1318 if (tcell->cell == 1) cellOne = tcell;
1321 ReleaseReadLock(&afs_xcell);
1322 if (!tcell) { /* no primary cell, use cell #1 */
1323 if (!cellOne) return ESRCH;
1326 strcpy(aout, tcell->cellName);
1327 *aoutSize = strlen(aout) + 1;
1331 static PGetUserCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1334 struct vrequest *areq;
1338 afs_int32 *aoutSize; /* set this */ {
1339 register afs_int32 i;
1340 register struct unixuser *tu;
1341 register struct cell *tcell;
1343 AFS_STATCNT(PGetUserCell);
1344 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1345 return EIO; /* Inappropriate ioctl for device */
1347 /* return the cell name of the primary cell for this user */
1348 i = UHash(areq->uid);
1349 ObtainWriteLock(&afs_xuser,224);
1350 for(tu = afs_users[i]; tu; tu = tu->next) {
1351 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1353 ReleaseWriteLock(&afs_xuser);
1358 tcell = afs_GetCell(tu->cell, READ_LOCK);
1359 afs_PutUser(tu, WRITE_LOCK);
1360 if (!tcell) return ESRCH;
1362 strcpy(aout, tcell->cellName);
1363 afs_PutCell(tcell, READ_LOCK);
1364 *aoutSize = strlen(aout)+1; /* 1 for the null */
1368 ReleaseWriteLock(&afs_xuser);
1375 static PSetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1378 struct vrequest *areq;
1382 afs_int32 *aoutSize; /* set this */
1383 struct AFS_UCRED **acred;
1386 register struct unixuser *tu;
1387 struct ClearToken clear;
1388 register struct cell *tcell;
1391 struct vrequest treq;
1392 afs_int32 flag, set_parent_pag = 0;
1394 AFS_STATCNT(PSetTokens);
1395 if (!afs_resourceinit_flag) {
1398 memcpy((char *)&i, ain, sizeof(afs_int32));
1399 ain += sizeof(afs_int32);
1400 stp = ain; /* remember where the ticket is */
1401 if (i < 0 || i > 2000) return EINVAL; /* malloc may fail */
1403 ain += i; /* skip over ticket */
1404 memcpy((char *)&i, ain, sizeof(afs_int32));
1405 ain += sizeof(afs_int32);
1406 if (i != sizeof(struct ClearToken)) {
1409 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1410 if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1411 ain += sizeof(struct ClearToken);
1412 if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1413 /* still stuff left? we've got primary flag and cell name. Set these */
1414 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1415 ain += sizeof(afs_int32); /* skip id field */
1416 /* rest is cell name, look it up */
1417 if (flag & 0x8000) { /* XXX Use Constant XXX */
1421 tcell = afs_GetCellByName(ain, READ_LOCK);
1430 /* default to cell 1, primary id */
1431 flag = 1; /* primary id */
1432 i = 1; /* cell number */
1433 tcell = afs_GetCell(1, READ_LOCK);
1434 if (!tcell) goto nocell;
1436 afs_PutCell(tcell, READ_LOCK);
1437 if (set_parent_pag) {
1439 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1440 struct proc *p=current_proc(); /* XXX */
1441 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1442 p->p_pid, p->p_comm);
1443 if (!setpag(p, acred, -1, &pag, 1)) {
1446 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1448 if (!setpag(acred, -1, &pag, 1)) {
1451 afs_InitReq(&treq, *acred);
1455 /* now we just set the tokens */
1456 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1457 tu->vid = clear.ViceId;
1458 if (tu->stp != (char *) 0) {
1459 afs_osi_Free(tu->stp, tu->stLen);
1461 tu->stp = (char *) afs_osi_Alloc(stLen);
1463 memcpy(tu->stp, stp, stLen);
1466 afs_stats_cmfullperf.authent.TicketUpdates++;
1467 afs_ComputePAGStats();
1468 #endif /* AFS_NOSTATS */
1469 tu->states |= UHasTokens;
1470 tu->states &= ~UTokensBad;
1471 afs_SetPrimary(tu, flag);
1472 tu->tokenTime =osi_Time();
1473 afs_ResetUserConns(tu);
1474 afs_PutUser(tu, WRITE_LOCK);
1489 static PGetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1492 struct vrequest *areq;
1495 afs_int32 *aoutSize; /* set this */ {
1497 char offLineMsg[256];
1499 register struct conn *tc;
1500 register afs_int32 code;
1501 struct VolumeStatus volstat;
1503 char *Name, *OfflineMsg, *MOTD;
1506 AFS_STATCNT(PGetVolumeStatus);
1507 if (!avc) return EINVAL;
1509 OfflineMsg = offLineMsg;
1512 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1514 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1515 #ifdef RX_ENABLE_LOCKS
1517 #endif /* RX_ENABLE_LOCKS */
1518 code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1519 &Name, &OfflineMsg, &MOTD);
1520 #ifdef RX_ENABLE_LOCKS
1522 #endif /* RX_ENABLE_LOCKS */
1527 (afs_Analyze(tc, code, &avc->fid, areq,
1528 AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1529 SHARED_LOCK, (struct cell *)0));
1531 if (code) return code;
1532 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1534 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1535 cp += sizeof(VolumeStatus);
1536 strcpy(cp, volName);
1537 cp += strlen(volName)+1;
1538 strcpy(cp, offLineMsg);
1539 cp += strlen(offLineMsg)+1;
1541 cp += strlen(motd)+1;
1542 *aoutSize = (cp - aout);
1546 static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1549 struct vrequest *areq;
1552 afs_int32 *aoutSize; /* set this */ {
1554 char offLineMsg[256];
1556 register struct conn *tc;
1557 register afs_int32 code;
1558 struct AFSFetchVolumeStatus volstat;
1559 struct AFSStoreVolumeStatus storeStat;
1560 register struct volume *tvp;
1564 AFS_STATCNT(PSetVolumeStatus);
1565 if (!avc) return EINVAL;
1567 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1569 if (tvp->states & (VRO | VBackup)) {
1570 afs_PutVolume(tvp, READ_LOCK);
1573 afs_PutVolume(tvp, READ_LOCK);
1576 /* Copy the junk out, using cp as a roving pointer. */
1578 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1579 cp += sizeof(AFSFetchVolumeStatus);
1580 if (strlen(cp) >= sizeof(volName))
1582 strcpy(volName, cp);
1583 cp += strlen(volName)+1;
1584 if (strlen(cp) >= sizeof(offLineMsg))
1586 strcpy(offLineMsg, cp);
1587 cp += strlen(offLineMsg)+1;
1588 if (strlen(cp) >= sizeof(motd))
1592 if (volstat.MinQuota != -1) {
1593 storeStat.MinQuota = volstat.MinQuota;
1594 storeStat.Mask |= AFS_SETMINQUOTA;
1596 if (volstat.MaxQuota != -1) {
1597 storeStat.MaxQuota = volstat.MaxQuota;
1598 storeStat.Mask |= AFS_SETMAXQUOTA;
1601 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1603 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1604 #ifdef RX_ENABLE_LOCKS
1606 #endif /* RX_ENABLE_LOCKS */
1607 code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1608 &storeStat, volName, offLineMsg, motd);
1609 #ifdef RX_ENABLE_LOCKS
1611 #endif /* RX_ENABLE_LOCKS */
1616 (afs_Analyze(tc, code, &avc->fid, areq,
1617 AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1618 SHARED_LOCK, (struct cell *)0));
1620 if (code) return code;
1621 /* we are sending parms back to make compat. with prev system. should
1622 change interface later to not ask for current status, just set new status */
1624 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1625 cp += sizeof(VolumeStatus);
1626 strcpy(cp, volName);
1627 cp += strlen(volName)+1;
1628 strcpy(cp, offLineMsg);
1629 cp += strlen(offLineMsg)+1;
1631 cp += strlen(motd)+1;
1632 *aoutSize = cp - aout;
1636 static PFlush(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1637 register struct vcache *avc;
1639 struct vrequest *areq;
1642 afs_int32 *aoutSize; /* set this */
1643 struct AFS_UCRED *acred;
1646 AFS_STATCNT(PFlush);
1647 if (!avc) return EINVAL;
1648 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1649 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1651 ObtainWriteLock(&avc->lock,225);
1652 ObtainWriteLock(&afs_xcbhash, 456);
1653 afs_DequeueCallback(avc);
1654 avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
1655 ReleaseWriteLock(&afs_xcbhash);
1656 /* now find the disk cache entries */
1657 afs_TryToSmush(avc, acred, 1);
1658 osi_dnlc_purgedp(avc);
1659 afs_symhint_inval(avc);
1660 if (avc->linkData && !(avc->states & CCore)) {
1661 afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1662 avc->linkData = (char *) 0;
1664 ReleaseWriteLock(&avc->lock);
1665 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1666 afs_BozonUnlock(&avc->pvnLock, avc);
1671 static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
1674 struct vrequest *areq;
1677 afs_int32 *aoutSize; /* set this */ {
1678 register afs_int32 code;
1679 register struct vcache *tvc;
1680 register struct dcache *tdc;
1681 struct VenusFid tfid;
1683 struct sysname_info sysState;
1684 afs_size_t offset, len;
1686 AFS_STATCNT(PNewStatMount);
1687 if (!avc) return EINVAL;
1688 code = afs_VerifyVCache(avc, areq);
1689 if (code) return code;
1690 if (vType(avc) != VDIR) {
1693 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1694 if (!tdc) return ENOENT;
1695 Check_AtSys(avc, ain, &sysState, areq);
1697 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1698 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1699 bufp = sysState.name;
1704 tfid.Cell = avc->fid.Cell;
1705 tfid.Fid.Volume = avc->fid.Fid.Volume;
1706 afs_PutDCache(tdc); /* we're done with the data */
1707 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1708 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
1710 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
1717 if (vType(tvc) != VLNK) {
1718 afs_PutVCache(tvc, WRITE_LOCK);
1722 ObtainWriteLock(&tvc->lock,226);
1723 code = afs_HandleLink(tvc, areq);
1725 if (tvc->linkData) {
1726 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1729 /* we have the data */
1730 strcpy(aout, tvc->linkData);
1731 *aoutSize = strlen(tvc->linkData)+1;
1736 ReleaseWriteLock(&tvc->lock);
1737 afs_PutVCache(tvc, WRITE_LOCK);
1739 if (sysState.allocked) osi_FreeLargeSpace(bufp);
1743 static PGetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize)
1746 struct vrequest *areq;
1749 afs_int32 *aoutSize; /* set this */ {
1750 register struct cell *tcell;
1751 register afs_int32 i;
1752 register struct unixuser *tu;
1757 AFS_STATCNT(PGetTokens);
1758 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1759 return EIO; /* Inappropriate ioctl for device */
1761 /* weird interface. If input parameter is present, it is an integer and
1762 we're supposed to return the parm'th tokens for this unix uid.
1763 If not present, we just return tokens for cell 1.
1764 If counter out of bounds, return EDOM.
1765 If no tokens for the particular cell, return ENOTCONN.
1766 Also, if this mysterious parm is present, we return, along with the
1767 tokens, the primary cell indicator (an afs_int32 0) and the cell name
1768 at the end, in that order.
1770 if (newStyle = (ainSize > 0)) {
1771 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1773 i = UHash(areq->uid);
1774 ObtainReadLock(&afs_xuser);
1775 for(tu = afs_users[i]; tu; tu=tu->next) {
1777 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1778 if (iterator-- == 0) break; /* are we done yet? */
1782 if (tu->uid == areq->uid && tu->cell == 1) break;
1787 * No need to hold a read lock on each user entry
1791 ReleaseReadLock(&afs_xuser);
1796 if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1797 tu->states |= (UTokensBad | UNeedsReset);
1798 afs_PutUser(tu, READ_LOCK);
1801 /* use iterator for temp */
1803 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1804 if (iterator < 56) iterator = 56; /* # of bytes we're returning */
1805 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1806 cp += sizeof(afs_int32);
1807 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1809 iterator = sizeof(struct ClearToken);
1810 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1811 cp += sizeof(afs_int32);
1812 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1813 cp += sizeof(struct ClearToken);
1815 /* put out primary id and cell name, too */
1816 iterator = (tu->states & UPrimary ? 1 : 0);
1817 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1818 cp += sizeof(afs_int32);
1819 tcell = afs_GetCell(tu->cell, READ_LOCK);
1821 strcpy(cp, tcell->cellName);
1822 cp += strlen(tcell->cellName)+1;
1823 afs_PutCell(tcell, READ_LOCK);
1827 *aoutSize = cp - aout;
1828 afs_PutUser(tu, READ_LOCK);
1832 static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
1835 struct vrequest *areq;
1838 afs_int32 *aoutSize; /* set this */ {
1839 register afs_int32 i;
1840 register struct unixuser *tu;
1842 AFS_STATCNT(PUnlog);
1843 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1844 return EIO; /* Inappropriate ioctl for device */
1846 i = UHash(areq->uid);
1847 ObtainWriteLock(&afs_xuser,227);
1848 for(tu=afs_users[i]; tu; tu=tu->next) {
1849 if (tu->uid == areq->uid) {
1851 tu->states &= ~UHasTokens;
1852 /* security is not having to say you're sorry */
1853 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
1855 ReleaseWriteLock(&afs_xuser);
1856 /* We have to drop the lock over the call to afs_ResetUserConns, since
1857 * it obtains the afs_xvcache lock. We could also keep the lock, and
1858 * modify ResetUserConns to take parm saying we obtained the lock
1859 * already, but that is overkill. By keeping the "tu" pointer
1860 * held over the released lock, we guarantee that we won't lose our
1861 * place, and that we'll pass over every user conn that existed when
1862 * we began this call.
1864 afs_ResetUserConns(tu);
1866 ObtainWriteLock(&afs_xuser,228);
1868 /* set the expire times to 0, causes
1869 * afs_GCUserData to remove this entry
1871 tu->ct.EndTimestamp = 0;
1873 #endif /* UKERNEL */
1876 ReleaseWriteLock(&afs_xuser);
1880 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1883 struct vrequest *areq;
1886 afs_int32 *aoutSize; /* set this */ {
1887 afs_int32 newHostAddr;
1888 afs_int32 oldHostAddr;
1890 AFS_STATCNT(PMariner);
1892 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost, sizeof(afs_int32));
1894 oldHostAddr = 0xffffffff; /* disabled */
1896 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
1897 if (newHostAddr == 0xffffffff) {
1898 /* disable mariner operations */
1901 else if (newHostAddr) {
1903 afs_marinerHost = newHostAddr;
1905 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
1906 *aoutSize = sizeof(afs_int32);
1910 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1913 struct vrequest *areq;
1916 afs_int32 *aoutSize; /* set this */
1917 struct AFS_UCRED *acred;
1919 register char *cp = 0;
1921 register struct server *ts;
1922 afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1924 struct chservinfo *pcheck;
1926 AFS_STATCNT(PCheckServers);
1928 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1929 return EIO; /* Inappropriate ioctl for device */
1931 if (*lp == 0x12345678) { /* For afs3.3 version */
1932 pcheck=(struct chservinfo *)ain;
1933 if (pcheck->tinterval >= 0) {
1935 memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
1936 *aoutSize = sizeof(afs_int32);
1937 if (pcheck->tinterval > 0) {
1938 if (!afs_osi_suser(acred))
1940 PROBE_INTERVAL=pcheck->tinterval;
1946 temp=pcheck->tflags;
1947 cp = pcheck->tbuffer;
1948 } else { /* For pre afs3.3 versions */
1949 memcpy((char *)&temp, ain, sizeof(afs_int32));
1950 cp = ain+sizeof(afs_int32);
1951 if (ainSize > sizeof(afs_int32))
1956 * 1: fast check, don't contact servers.
1957 * 2: local cell only.
1960 /* have cell name, too */
1961 cellp = afs_GetCellByName(cp, READ_LOCK);
1962 if (!cellp) return ENOENT;
1964 else cellp = (struct cell *) 0;
1965 if (!cellp && (temp & 2)) {
1966 /* use local cell */
1967 cellp = afs_GetCell(1, READ_LOCK);
1969 if (!(temp & 1)) { /* if not fast, call server checker routine */
1970 afs_CheckServers(1, cellp); /* check down servers */
1971 afs_CheckServers(0, cellp); /* check up servers */
1973 /* now return the current down server list */
1975 ObtainReadLock(&afs_xserver);
1976 for(i=0;i<NSERVERS;i++) {
1977 for(ts = afs_servers[i]; ts; ts=ts->next) {
1978 if (cellp && ts->cell != cellp) continue; /* cell spec'd and wrong */
1979 if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1980 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
1981 cp += sizeof(afs_int32);
1985 ReleaseReadLock(&afs_xserver);
1986 if (cellp) afs_PutCell(cellp, READ_LOCK);
1987 *aoutSize = cp - aout;
1991 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
1994 struct vrequest *areq;
1997 afs_int32 *aoutSize; /* set this */ {
1998 AFS_STATCNT(PCheckVolNames);
1999 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2000 return EIO; /* Inappropriate ioctl for device */
2002 afs_CheckRootVolume();
2003 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
2004 AFS_VOLCHECK_EXPIRED |
2006 AFS_VOLCHECK_MTPTS);
2010 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
2013 struct vrequest *areq;
2016 afs_int32 *aoutSize; /* set this */ {
2020 struct unixuser *tu;
2022 extern afs_rwlock_t afs_xsrvAddr;
2024 AFS_STATCNT(PCheckAuth);
2025 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2026 return EIO; /* Inappropriate ioctl for device */
2029 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2030 if (!tu) retValue = EACCES;
2032 /* we have a user */
2033 ObtainReadLock(&afs_xsrvAddr);
2034 ObtainReadLock(&afs_xconn);
2036 /* any tokens set? */
2037 if ((tu->states & UHasTokens) == 0) retValue = EACCES;
2038 /* all connections in cell 1 working? */
2039 for(i=0;i<NSERVERS;i++) {
2040 for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
2041 for (tc = sa->conns; tc; tc=tc->next) {
2042 if (tc->user == tu && (tu->states & UTokensBad))
2047 ReleaseReadLock(&afs_xsrvAddr);
2048 ReleaseReadLock(&afs_xconn);
2049 afs_PutUser(tu, READ_LOCK);
2051 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2052 *aoutSize = sizeof(afs_int32);
2056 static Prefetch(apath, adata, afollow, acred)
2058 struct afs_ioctl *adata;
2060 struct AFS_UCRED *acred;
2063 register afs_int32 code;
2064 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2070 AFS_STATCNT(Prefetch);
2071 if (!apath) return EINVAL;
2072 tp = osi_AllocLargeSpace(1024);
2073 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2075 osi_FreeLargeSpace(tp);
2078 if (afs_BBusy()) { /* do this as late as possible */
2079 osi_FreeLargeSpace(tp);
2080 return EWOULDBLOCK; /* pretty close */
2082 afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred,
2083 (afs_size_t) 0, (afs_size_t) 0, tp);
2087 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
2090 struct vrequest *areq;
2093 afs_int32 *aoutSize; /* set this */ {
2094 register struct volume *tvp;
2095 register struct server *ts;
2096 register afs_int32 i;
2099 AFS_STATCNT(PFindVolume);
2100 if (!avc) return EINVAL;
2101 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2104 for(i=0;i<MAXHOSTS;i++) {
2105 ts = tvp->serverHost[i];
2107 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2108 cp += sizeof(afs_int32);
2111 /* still room for terminating NULL, add it on */
2112 ainSize = 0; /* reuse vbl */
2113 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2114 cp += sizeof(afs_int32);
2116 *aoutSize = cp - aout;
2117 afs_PutVolume(tvp, READ_LOCK);
2123 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
2126 struct vrequest *areq;
2129 afs_int32 *aoutSize; /* set this */ {
2130 register afs_int32 code;
2133 AFS_STATCNT(PViceAccess);
2134 if (!avc) return EINVAL;
2135 code = afs_VerifyVCache(avc, areq);
2136 if (code) return code;
2137 memcpy((char *)&temp, ain, sizeof(afs_int32));
2138 code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2143 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2146 struct vrequest *areq;
2149 afs_int32 *aoutSize; /* set this */
2150 struct AFS_UCRED *acred;
2155 AFS_STATCNT(PSetCacheSize);
2156 if (!afs_osi_suser(acred))
2158 /* too many things are setup initially in mem cache version */
2159 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2160 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2161 if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2163 extern u_int afs_min_cache;
2164 if (newValue < afs_min_cache)
2165 afs_cacheBlocks = afs_min_cache;
2167 afs_cacheBlocks = newValue;
2169 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2170 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2171 afs_MaybeWakeupTruncateDaemon();
2172 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2173 afs_osi_Wait(1000, 0, 0);
2174 afs_MaybeWakeupTruncateDaemon();
2179 #define MAXGCSTATS 16
2180 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2183 struct vrequest *areq;
2186 afs_int32 *aoutSize; /* set this */ {
2187 afs_int32 results[MAXGCSTATS];
2189 AFS_STATCNT(PGetCacheSize);
2190 memset((char *)results, 0, sizeof(results));
2191 results[0] = afs_cacheBlocks;
2192 results[1] = afs_blocksUsed;
2193 memcpy(aout, (char *)results, sizeof(results));
2194 *aoutSize = sizeof(results);
2198 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2201 struct vrequest *areq;
2204 afs_int32 *aoutSize; /* set this */ {
2205 register struct conn *tc;
2206 register afs_int32 code;
2207 struct AFSCallBack CallBacks_Array[1];
2208 struct AFSCBFids theFids;
2209 struct AFSCBs theCBs;
2212 AFS_STATCNT(PRemoveCallBack);
2213 if (!avc) return EINVAL;
2214 if (avc->states & CRO) return 0; /* read-only-ness can't change */
2215 ObtainWriteLock(&avc->lock,229);
2216 theFids.AFSCBFids_len = 1;
2217 theCBs.AFSCBs_len = 1;
2218 theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2219 theCBs.AFSCBs_val = CallBacks_Array;
2220 CallBacks_Array[0].CallBackType = CB_DROPPED;
2221 if (avc->callback) {
2223 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2225 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2226 #ifdef RX_ENABLE_LOCKS
2228 #endif /* RX_ENABLE_LOCKS */
2229 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2230 #ifdef RX_ENABLE_LOCKS
2232 #endif /* RX_ENABLE_LOCKS */
2235 /* don't set code on failure since we wouldn't use it */
2237 (afs_Analyze(tc, code, &avc->fid, areq,
2238 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2239 SHARED_LOCK, (struct cell *)0));
2241 ObtainWriteLock(&afs_xcbhash, 457);
2242 afs_DequeueCallback(avc);
2244 avc->states &= ~(CStatd | CUnique);
2245 ReleaseWriteLock(&afs_xcbhash);
2246 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2247 osi_dnlc_purgedp(avc);
2249 ReleaseWriteLock(&avc->lock);
2253 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2256 struct vrequest *areq;
2260 struct AFS_UCRED *acred;
2261 afs_int32 *aoutSize; /* set this */ {
2262 /* create a new cell */
2263 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2264 register struct cell *tcell;
2265 char *newcell=0, *linkedcell=0, *tp= ain;
2266 register afs_int32 code, linkedstate=0, ls;
2267 u_short fsport = 0, vlport = 0;
2270 AFS_STATCNT(PNewCell);
2271 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2272 return EIO; /* Inappropriate ioctl for device */
2274 if (!afs_osi_suser(acred))
2277 memcpy((char *)&magic, tp, sizeof(afs_int32));
2278 tp += sizeof(afs_int32);
2279 if (magic != 0x12345678)
2282 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2283 * server addresses while the 3.5 fs newcell command passes
2284 * MAXHOSTS. To figure out which is which, check if the cellname
2287 newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2288 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2290 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2291 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2292 tp += (scount * sizeof(afs_int32));
2294 lp = (afs_int32 *)tp;
2297 if (fsport < 1024) fsport = 0; /* Privileged ports not allowed */
2298 if (vlport < 1024) vlport = 0; /* Privileged ports not allowed */
2299 tp += (3 * sizeof(afs_int32));
2301 if ((ls = *lp) & 1) {
2302 linkedcell = tp + strlen(newcell)+1;
2303 linkedstate |= CLinkedCell;
2306 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2307 code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0, (char *) 0);
2311 static PNewAlias(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2314 struct vrequest *areq;
2318 struct AFS_UCRED *acred;
2319 afs_int32 *aoutSize; /* set this */
2321 /* create a new cell alias */
2322 register struct cell *tcell;
2324 register afs_int32 code;
2325 char *realName, *aliasName;
2326 register struct afs_q *cq, *tq;
2328 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2329 return EIO; /* Inappropriate ioctl for device */
2331 if (!afs_osi_suser(acred))
2335 tp += strlen(aliasName) + 1;
2339 * Prevent user from shooting themselves in the foot -- don't allow
2340 * creation of aliases when a real cell already exists with that name.
2342 ObtainReadLock(&afs_xcell);
2343 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2344 tcell = QTOC(cq); tq = QNext(cq);
2345 if ((afs_strcasecmp(tcell->cellName, aliasName) == 0) &&
2346 !(tcell->states & CAlias)) {
2347 ReleaseReadLock(&afs_xcell);
2351 ReleaseReadLock(&afs_xcell);
2353 code = afs_NewCell(aliasName, 0, CAlias, 0, 0, 0, 0, realName);
2358 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2361 struct vrequest *areq;
2364 afs_int32 *aoutSize; /* set this */ {
2365 afs_int32 whichCell;
2366 register struct cell *tcell=0;
2367 register afs_int32 i;
2368 register char *cp, *tp = ain;
2369 register struct afs_q *cq, *tq;
2371 AFS_STATCNT(PListCells);
2372 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2373 return EIO; /* Inappropriate ioctl for device */
2375 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2376 tp += sizeof(afs_int32);
2377 ObtainReadLock(&afs_xcell);
2378 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2379 tcell = QTOC(cq); tq = QNext(cq);
2380 if (tcell->states & CAlias) {
2384 if (whichCell == 0) break;
2390 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2391 for(i=0;i<MAXCELLHOSTS;i++) {
2392 if (tcell->cellHosts[i] == 0) break;
2393 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip, sizeof(afs_int32));
2394 cp += sizeof(afs_int32);
2396 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2397 strcpy(cp, tcell->cellName);
2398 cp += strlen(tcell->cellName)+1;
2399 *aoutSize = cp - aout;
2401 ReleaseReadLock(&afs_xcell);
2402 if (tcell) return 0;
2406 static PListAliases(avc, afun, areq, ain, aout, ainSize, aoutSize)
2409 struct vrequest *areq;
2412 afs_int32 *aoutSize; /* set this */
2414 afs_int32 whichAlias;
2415 register struct cell *tcell=0;
2416 register char *cp, *tp = ain;
2417 register struct afs_q *cq, *tq;
2419 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2420 return EIO; /* Inappropriate ioctl for device */
2421 if (ainSize < sizeof(afs_int32))
2424 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2425 tp += sizeof(afs_int32);
2427 ObtainReadLock(&afs_xcell);
2428 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2429 tcell = QTOC(cq); tq = QNext(cq);
2430 if (!(tcell->states & CAlias)) {
2434 if (whichAlias == 0) break;
2440 strcpy(cp, tcell->cellName);
2441 cp += strlen(tcell->cellName)+1;
2442 strcpy(cp, tcell->realName);
2443 cp += strlen(tcell->realName)+1;
2444 *aoutSize = cp - aout;
2446 ReleaseReadLock(&afs_xcell);
2447 if (tcell) return 0;
2451 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2454 struct vrequest *areq;
2458 afs_int32 *aoutSize; /* set this */ {
2459 register afs_int32 code;
2461 struct sysname_info sysState;
2462 afs_size_t offset, len;
2463 register struct conn *tc;
2464 register struct dcache *tdc;
2465 register struct vcache *tvc;
2466 struct AFSFetchStatus OutDirStatus;
2467 struct VenusFid tfid;
2468 struct AFSVolSync tsync;
2472 /* "ain" is the name of the file in this dir to remove */
2474 AFS_STATCNT(PRemoveMount);
2475 if (!avc) return EINVAL;
2476 code = afs_VerifyVCache(avc, areq);
2477 if (code) return code;
2478 if (vType(avc) != VDIR) return ENOTDIR;
2480 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2481 if (!tdc) return ENOENT;
2482 Check_AtSys(avc, ain, &sysState, areq);
2484 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2485 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2486 bufp = sysState.name;
2491 tfid.Cell = avc->fid.Cell;
2492 tfid.Fid.Volume = avc->fid.Fid.Volume;
2493 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2494 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2496 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2497 (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2504 if (vType(tvc) != VLNK) {
2506 afs_PutVCache(tvc, WRITE_LOCK);
2510 ObtainWriteLock(&tvc->lock,230);
2511 code = afs_HandleLink(tvc, areq);
2513 if (tvc->linkData) {
2514 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2519 ReleaseWriteLock(&tvc->lock);
2520 osi_dnlc_purgedp(tvc);
2521 afs_PutVCache(tvc, WRITE_LOCK);
2526 ObtainWriteLock(&avc->lock,231);
2527 osi_dnlc_remove(avc, bufp, tvc);
2529 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2531 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2532 #ifdef RX_ENABLE_LOCKS
2534 #endif /* RX_ENABLE_LOCKS */
2535 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2536 bufp, &OutDirStatus, &tsync);
2537 #ifdef RX_ENABLE_LOCKS
2539 #endif /* RX_ENABLE_LOCKS */
2544 (afs_Analyze(tc, code, &avc->fid, areq,
2545 AFS_STATS_FS_RPCIDX_REMOVEFILE,
2546 SHARED_LOCK, (struct cell *)0));
2549 if (tdc) afs_PutDCache(tdc);
2550 ReleaseWriteLock(&avc->lock);
2554 /* we have the thing in the cache */
2555 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2556 /* we can do it locally */
2557 code = afs_dir_Delete(&tdc->f.inode, bufp);
2559 ZapDCE(tdc); /* surprise error -- invalid value */
2560 DZap(&tdc->f.inode);
2563 afs_PutDCache(tdc); /* drop ref count */
2565 avc->states &= ~CUnique; /* For the dfs xlator */
2566 ReleaseWriteLock(&avc->lock);
2569 if (sysState.allocked) osi_FreeLargeSpace(bufp);
2573 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2576 struct vrequest *areq;
2580 struct AFS_UCRED *acred;
2581 afs_int32 *aoutSize; /* set this */ {
2582 return EINVAL; /* OBSOLETE */
2585 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2588 struct vrequest *areq;
2591 afs_int32 *aoutSize; /* set this */ {
2592 register struct cell *tcell;
2595 AFS_STATCNT(PGetCellStatus);
2596 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2597 return EIO; /* Inappropriate ioctl for device */
2599 tcell = afs_GetCellByName(ain, READ_LOCK);
2600 if (!tcell) return ENOENT;
2601 temp = tcell->states;
2602 afs_PutCell(tcell, READ_LOCK);
2603 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2604 *aoutSize = sizeof(afs_int32);
2608 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2611 struct vrequest *areq;
2614 struct AFS_UCRED *acred;
2615 afs_int32 *aoutSize; /* set this */ {
2616 register struct cell *tcell;
2619 if (!afs_osi_suser(acred))
2621 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2622 return EIO; /* Inappropriate ioctl for device */
2624 tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2625 if (!tcell) return ENOENT;
2626 memcpy((char *)&temp, ain, sizeof(afs_int32));
2628 tcell->states |= CNoSUID;
2630 tcell->states &= ~CNoSUID;
2631 afs_PutCell(tcell, WRITE_LOCK);
2635 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2638 struct vrequest *areq;
2641 afs_int32 *aoutSize; /* set this */
2642 struct AFS_UCRED *acred;
2644 extern struct volume *afs_volumes[NVOLS];
2645 register afs_int32 i;
2646 register struct dcache *tdc;
2647 register struct vcache *tvc;
2648 register struct volume *tv;
2649 afs_int32 cell, volume;
2651 AFS_STATCNT(PFlushVolumeData);
2654 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2655 return EIO; /* Inappropriate ioctl for device */
2657 volume = avc->fid.Fid.Volume; /* who to zap */
2658 cell = avc->fid.Cell;
2661 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2662 * the vcaches associated with the volume.
2664 ObtainReadLock(&afs_xvcache);
2665 for(i = 0; i < VCSIZE; i++) {
2666 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2667 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2668 #if defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2669 VN_HOLD((struct vnode *)tvc);
2671 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2677 ReleaseReadLock(&afs_xvcache);
2678 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2679 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
2681 ObtainWriteLock(&tvc->lock,232);
2683 ObtainWriteLock(&afs_xcbhash, 458);
2684 afs_DequeueCallback(tvc);
2685 tvc->states &= ~(CStatd | CDirty);
2686 ReleaseWriteLock(&afs_xcbhash);
2687 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2688 osi_dnlc_purgedp(tvc);
2689 afs_TryToSmush(tvc, acred, 1);
2690 ReleaseWriteLock(&tvc->lock);
2691 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2692 afs_BozonUnlock(&tvc->pvnLock, tvc);
2694 ObtainReadLock(&afs_xvcache);
2695 /* our tvc ptr is still good until now */
2700 ReleaseReadLock(&afs_xvcache);
2703 MObtainWriteLock(&afs_xdcache,328); /* needed if you're going to flush any stuff */
2704 for(i=0;i<afs_cacheFiles;i++) {
2705 if (!(afs_indexFlags[i] & IFEverUsed)) continue; /* never had any data */
2706 tdc = afs_GetDSlot(i, (struct dcache *) 0);
2707 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
2708 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2709 if (! (afs_indexFlags[i] & IFDataMod)) {
2710 /* if the file is modified, but has a ref cnt of only 1, then
2711 someone probably has the file open and is writing into it.
2712 Better to skip flushing such a file, it will be brought back
2713 immediately on the next write anyway.
2715 If we *must* flush, then this code has to be rearranged to call
2716 afs_storeAllSegments() first */
2717 afs_FlushDCache(tdc);
2721 tdc->refCount--; /* bumped by getdslot */
2723 MReleaseWriteLock(&afs_xdcache);
2725 ObtainReadLock(&afs_xvolume);
2726 for (i=0;i<NVOLS;i++) {
2727 for (tv = afs_volumes[i]; tv; tv=tv->next) {
2728 if (tv->volume == volume) {
2729 afs_ResetVolumeInfo(tv);
2734 ReleaseReadLock(&afs_xvolume);
2736 /* probably, a user is doing this, probably, because things are screwed up.
2737 * maybe it's the dnlc's fault? */
2744 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2747 struct vrequest *areq;
2750 afs_int32 *aoutSize; /* set this */ {
2751 register afs_int32 code;
2752 struct vcxstat stat;
2755 /* AFS_STATCNT(PGetVnodeXStatus); */
2756 if (!avc) return EINVAL;
2757 code = afs_VerifyVCache(avc, areq);
2758 if (code) return code;
2759 if (vType(avc) == VDIR)
2760 mode = PRSFS_LOOKUP;
2763 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2765 stat.fid = avc->fid;
2766 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2767 stat.lock = avc->lock;
2768 stat.parentVnode = avc->parentVnode;
2769 stat.parentUnique = avc->parentUnique;
2770 hset(stat.flushDV, avc->flushDV);
2771 hset(stat.mapDV, avc->mapDV);
2772 stat.truncPos = avc->truncPos;
2773 { /* just grab the first two - won't break anything... */
2774 struct axscache *ac;
2776 for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2777 stat.randomUid[i] = ac->uid;
2778 stat.randomAccess[i] = ac->axess;
2781 stat.callback = afs_data_pointer_to_int32(avc->callback);
2782 stat.cbExpires = avc->cbExpires;
2783 stat.anyAccess = avc->anyAccess;
2784 stat.opens = avc->opens;
2785 stat.execsOrWriters = avc->execsOrWriters;
2786 stat.flockCount = avc->flockCount;
2787 stat.mvstat = avc->mvstat;
2788 stat.states = avc->states;
2789 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
2790 *aoutSize = sizeof(struct vcxstat);
2795 /* We require root for local sysname changes, but not for remote */
2796 /* (since we don't really believe remote uids anyway) */
2797 /* outname[] shouldn't really be needed- this is left as an excercise */
2798 /* for the reader. */
2799 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2802 struct vrequest *areq;
2805 afs_int32 *aoutSize; /* set this */
2806 register struct AFS_UCRED *acred;
2808 char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2809 int setsysname, foundname=0;
2810 register struct afs_exporter *exporter;
2811 extern struct unixuser *afs_FindUser();
2812 extern char *afs_sysname;
2813 extern char *afs_sysnamelist[];
2814 extern int afs_sysnamecount;
2815 register struct unixuser *au;
2816 register afs_int32 pag, error;
2820 AFS_STATCNT(PSetSysName);
2821 if (!afs_globalVFS) {
2822 /* Afsd is NOT running; disable it */
2823 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2826 return (setuerror(EINVAL), EINVAL);
2829 memset(inname, 0, MAXSYSNAME);
2830 memcpy((char *)&setsysname, ain, sizeof(afs_int32));
2831 ain += sizeof(afs_int32);
2835 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2837 for(cp = ain,count = 0;count < setsysname;count++) {
2838 /* won't go past end of ain since maxsysname*num < ain length */
2840 if (t >= MAXSYSNAME || t <= 0)
2842 /* check for names that can shoot us in the foot */
2843 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2849 /* inname gets first entry in case we're being a translater */
2851 memcpy(inname, ain, t+1); /* include terminating null */
2854 if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2855 pag = PagInCred(acred);
2857 return EINVAL; /* Better than panicing */
2859 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2860 return EINVAL; /* Better than panicing */
2862 if (!(exporter = au->exporter)) {
2863 afs_PutUser(au, READ_LOCK);
2864 return EINVAL; /* Better than panicing */
2866 error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2868 if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2870 afs_PutUser(au, READ_LOCK);
2875 afs_PutUser(au, READ_LOCK);
2878 /* Not xlating, so local case */
2879 if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2880 if (!setsysname) { /* user just wants the info */
2881 strcpy(outname, afs_sysname);
2882 foundname = afs_sysnamecount;
2883 } else { /* Local guy; only root can change sysname */
2884 if (!afs_osi_suser(acred))
2887 /* clear @sys entries from the dnlc, once afs_lookup can
2888 do lookups of @sys entries and thinks it can trust them */
2889 /* privs ok, store the entry, ... */
2890 strcpy(afs_sysname, inname);
2891 if (setsysname > 1) { /* ... or list */
2893 for(count=1; count < setsysname;++count) {
2894 if (!afs_sysnamelist[count])
2895 osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2897 memcpy(afs_sysnamelist[count], cp, t+1); /* include null */
2901 afs_sysnamecount = setsysname;
2905 cp = aout; /* not changing so report back the count and ... */
2906 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
2907 cp += sizeof(afs_int32);
2909 strcpy(cp, outname); /* ... the entry, ... */
2910 cp += strlen(outname)+1;
2911 for(count=1; count < foundname; ++count) { /* ... or list. */
2912 /* Note: we don't support @sys lists for exporters */
2913 if (!afs_sysnamelist[count])
2914 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2915 t = strlen(afs_sysnamelist[count]);
2916 if (t >= MAXSYSNAME)
2917 osi_Panic("PSetSysName: sysname entry garbled\n");
2918 strcpy(cp, afs_sysnamelist[count]);
2922 *aoutSize = cp - aout;
2927 /* sequential search through the list of touched cells is not a good
2928 * long-term solution here. For small n, though, it should be just
2929 * fine. Should consider special-casing the local cell for large n.
2930 * Likewise for PSetSPrefs.
2932 static void ReSortCells(s,l, vlonly)
2933 int s; /* number of ids in array l[] -- NOT index of last id */
2934 afs_int32 l[]; /* array of cell ids which have volumes that need to be sorted */
2935 int vlonly; /* sort vl servers or file servers?*/
2937 extern struct volume *afs_volumes[NVOLS]; /* volume hash table */
2945 ObtainWriteLock(&afs_xcell,300);
2947 tcell = afs_GetCellNoLock(l[k], WRITE_LOCK);
2948 if (!tcell) continue;
2949 afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2950 afs_PutCell(tcell, WRITE_LOCK);
2952 ReleaseWriteLock(&afs_xcell);
2956 ObtainReadLock(&afs_xvolume);
2957 for (i= 0; i< NVOLS; i++) {
2958 for (j=afs_volumes[i];j;j=j->next) {
2960 if (j->cell == l[k]) {
2961 ObtainWriteLock(&j->lock,233);
2962 afs_SortServers(j->serverHost, MAXHOSTS);
2963 ReleaseWriteLock(&j->lock);
2968 ReleaseReadLock(&afs_xvolume);
2973 static int afs_setsprefs(sp, num, vlonly)
2976 unsigned int vlonly;
2979 int i,j,k,matches,touchedSize;
2980 struct server *srvr = NULL;
2981 afs_int32 touched[34];
2985 for (k=0; k < num; sp++, k++) {
2987 printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2990 ObtainReadLock(&afs_xserver);
2992 i = SHash(sp->host.s_addr);
2993 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2994 if (sa->sa_ip == sp->host.s_addr) {
2996 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
2997 || (sa->sa_portal == AFS_FSPORT);
2998 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3005 if (sa && matches) { /* found one! */
3007 printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
3009 sa->sa_iprank = sp->rank + afs_randomMod15();
3010 afs_SortOneServer(sa->server);
3013 /* if we don't know yet what cell it's in, this is moot */
3014 for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
3015 /* is it in our list of touched cells ? */ ;
3016 if (j < 0) { /* no, it's not */
3017 touched[touchedSize++] = srvr->cell->cell;
3018 if (touchedSize >= 32) { /* watch for ovrflow */
3019 ReleaseReadLock(&afs_xserver);
3020 ReSortCells(touchedSize, touched, vlonly);
3022 ObtainReadLock(&afs_xserver);
3028 ReleaseReadLock(&afs_xserver);
3029 /* if we didn't find one, start to create one. */
3030 /* Note that it doesn't have a cell yet... */
3032 afs_uint32 temp = sp->host.s_addr;
3033 srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3034 WRITE_LOCK, (afsUUID *)0,0);
3035 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3036 afs_PutServer(srvr, WRITE_LOCK);
3038 } /* for all cited preferences */
3040 ReSortCells(touchedSize, touched, vlonly);
3044 /* Note that this may only be performed by the local root user.
3047 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3050 struct vrequest *areq;
3053 struct AFS_UCRED *acred;
3054 afs_int32 *aoutSize;
3056 struct setspref *ssp;
3057 AFS_STATCNT(PSetSPrefs);
3059 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3060 return EIO; /* Inappropriate ioctl for device */
3062 if (!afs_osi_suser(acred))
3065 if (ainSize < sizeof(struct setspref))
3068 ssp = (struct setspref *)ain;
3069 if (ainSize < sizeof(struct spref)*ssp->num_servers)
3072 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3073 (ssp->flags & DBservers));
3078 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3081 struct vrequest *areq;
3084 struct AFS_UCRED *acred;
3085 afs_int32 *aoutSize;
3088 AFS_STATCNT(PSetSPrefs);
3089 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3090 return EIO; /* Inappropriate ioctl for device */
3093 if (!afs_osi_suser(acred))
3096 sp = (struct spref *)ain;
3097 afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
3101 /* some notes on the following code...
3102 * in the hash table of server structs, all servers with the same IP address
3103 * will be on the same overflow chain.
3104 * This could be sped slightly in some circumstances by having it cache the
3105 * immediately previous slot in the hash table and some supporting information
3106 * Only reports file servers now.
3109 PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3112 struct vrequest *areq;
3115 afs_int32 *aoutSize;
3117 struct sprefrequest *spin; /* input */
3118 struct sprefinfo *spout; /* output */
3119 struct spref *srvout; /* one output component */
3120 int i,j; /* counters for hash table traversal */
3121 struct server *srvr; /* one of CM's server structs */
3124 int vlonly; /* just return vlservers ? */
3127 AFS_STATCNT(PGetSPrefs);
3128 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3129 return EIO; /* Inappropriate ioctl for device */
3132 if (ainSize < sizeof (struct sprefrequest_33)) {
3136 spin = ((struct sprefrequest *) ain);
3139 if (ainSize > sizeof (struct sprefrequest_33)) {
3140 vlonly = (spin->flags & DBservers);
3144 /* struct sprefinfo includes 1 server struct... that size gets added
3145 * in during the loop that follows.
3147 *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
3148 spout = (struct sprefinfo *) aout;
3149 spout->next_offset = spin->offset;
3150 spout->num_servers = 0;
3151 srvout = spout->servers;
3153 ObtainReadLock(&afs_xserver);
3154 for (i=0, j=0; j < NSERVERS; j++) { /* sift through hash table */
3155 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3156 if (spin->offset > (unsigned short)i) {
3157 continue; /* catch up to where we left off */
3159 spout->next_offset++;
3162 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3163 || (sa->sa_portal == AFS_FSPORT);
3165 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3166 /* only report ranks for vl servers */
3170 srvout->host.s_addr = sa->sa_ip;
3171 srvout->rank = sa->sa_iprank;
3172 *aoutSize += sizeof(struct spref);
3173 spout->num_servers++;
3176 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3177 ReleaseReadLock(&afs_xserver); /* no more room! */
3182 ReleaseReadLock(&afs_xserver);
3184 spout->next_offset = 0; /* start over from the beginning next time */
3188 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3189 int afs_NFSRootOnly = 1;
3190 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3193 struct vrequest *areq;
3196 afs_int32 *aoutSize; /* set this */
3197 struct AFS_UCRED *acred;
3199 afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3200 extern struct afs_exporter *exporter_find();
3201 register struct afs_exporter *exporter;
3203 AFS_STATCNT(PExportAfs);
3204 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3205 type = handleValue >> 24;
3210 exporter = exporter_find(type);
3212 export = handleValue & 3;
3213 changestate = handleValue & 0xff;
3214 smounts = (handleValue >> 2) & 3;
3215 pwsync = (handleValue >> 4) & 3;
3216 convmode = (handleValue >> 6) & 3;
3218 changestate = (handleValue >> 16) & 0x1;
3219 convmode = (handleValue >> 16) & 0x2;
3220 pwsync = (handleValue >> 16) & 0x4;
3221 smounts = (handleValue >> 16) & 0x8;
3222 export = handleValue & 0xff;
3225 /* Failed finding desired exporter; */
3229 handleValue = exporter->exp_states;
3230 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3231 *aoutSize = sizeof(afs_int32);
3233 if (!afs_osi_suser(acred))
3234 return EACCES; /* Only superuser can do this */
3238 exporter->exp_states |= EXP_EXPORTED;
3240 exporter->exp_states &= ~EXP_EXPORTED;
3244 exporter->exp_states |= EXP_UNIXMODE;
3246 exporter->exp_states &= ~EXP_UNIXMODE;
3250 exporter->exp_states |= EXP_PWSYNC;
3252 exporter->exp_states &= ~EXP_PWSYNC;
3256 afs_NFSRootOnly = 0;
3257 exporter->exp_states |= EXP_SUBMOUNTS;
3259 afs_NFSRootOnly = 1;
3260 exporter->exp_states &= ~EXP_SUBMOUNTS;
3263 handleValue = exporter->exp_states;
3264 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3265 *aoutSize = sizeof(afs_int32);
3268 exporter->exp_states |= EXP_EXPORTED;
3270 exporter->exp_states &= ~EXP_EXPORTED;
3272 exporter->exp_states |= EXP_UNIXMODE;
3274 exporter->exp_states &= ~EXP_UNIXMODE;
3276 exporter->exp_states |= EXP_PWSYNC;
3278 exporter->exp_states &= ~EXP_PWSYNC;
3280 afs_NFSRootOnly = 0;
3281 exporter->exp_states |= EXP_SUBMOUNTS;
3283 afs_NFSRootOnly = 1;
3284 exporter->exp_states &= ~EXP_SUBMOUNTS;
3293 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3296 struct vrequest *areq;
3299 struct AFS_UCRED *acred;
3300 afs_int32 *aoutSize; /* set this */
3302 struct gaginfo *gagflags;
3304 if (!afs_osi_suser(acred))
3307 gagflags = (struct gaginfo *) ain;
3308 afs_showflags = gagflags->showflags;
3315 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3318 struct vrequest *areq;
3321 struct AFS_UCRED *acred;
3322 afs_int32 *aoutSize;
3324 struct rxparams *rxp;
3326 if (!afs_osi_suser(acred))
3329 rxp = (struct rxparams *) ain;
3331 if (rxp->rx_initReceiveWindow)
3332 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3333 if (rxp->rx_maxReceiveWindow)
3334 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3335 if (rxp->rx_initSendWindow)
3336 rx_initSendWindow = rxp->rx_initSendWindow;
3337 if (rxp->rx_maxSendWindow)
3338 rx_maxSendWindow = rxp->rx_maxSendWindow;
3339 if (rxp->rxi_nSendFrags)
3340 rxi_nSendFrags = rxp->rxi_nSendFrags;
3341 if (rxp->rxi_nRecvFrags)
3342 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3343 if (rxp->rxi_OrphanFragSize)
3344 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3345 if (rxp->rx_maxReceiveSize)
3347 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3348 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3350 if (rxp->rx_MyMaxSendSize)
3351 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3356 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3359 struct vrequest *areq;
3363 afs_int32 *aoutSize; /* set this */
3365 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3368 memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3369 *aoutSize = sizeof(struct cm_initparams);
3373 #ifdef AFS_SGI65_ENV
3374 /* They took crget() from us, so fake it. */
3375 static cred_t *crget(void)
3378 cr = crdup(get_current_cred());
3379 memset((char*)cr, 0, sizeof(cred_t));
3380 #if CELL || CELL_PREPARE
3388 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3391 struct vrequest *areq;
3394 afs_int32 *aoutSize;
3395 struct AFS_UCRED *acred;
3397 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3398 *aoutSize=sizeof(afs_int32);
3403 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3406 struct vrequest *areq;
3409 afs_int32 *aoutSize;
3410 struct AFS_UCRED *acred;
3414 if (!afs_osi_suser(acred))
3416 if (ainSize != sizeof(afs_int32) || ain == NULL)
3418 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3419 /* if new mappings added later this will need to be changed */
3420 if (tmpval != 0 && tmpval != 1)
3427 * Create new credentials to correspond to a remote user with given
3428 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3429 * provide pioctl (and other) services to foreign clients (i.e. nfs
3430 * clients) by using this call to `become' the client.
3433 #define PIOCTL_HEADER 6
3434 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3437 afs_uint32 hostaddr;
3438 afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3439 extern struct afs_exporter *exporter_find();
3440 struct afs_exporter *exporter, *outexporter;
3441 struct AFS_UCRED *newcred;
3442 struct unixuser *au;
3444 #if defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3445 return EINVAL; /* NFS trans not supported for Ultrix */
3447 #if defined(AFS_SGIMP_ENV)
3448 osi_Assert(ISAFS_GLOCK());
3450 AFS_STATCNT(HandleClientContext);
3451 if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) {
3452 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3453 return EINVAL; /* Too small to be good */
3455 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3456 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3458 osi_FreeLargeSpace(inData);
3462 /* Extract information for remote user */
3463 hostaddr = *((afs_uint32 *)ain);
3464 ain += sizeof(hostaddr);
3465 uid = *((afs_uint32 *)ain);
3467 g0 = *((afs_uint32 *)ain);
3469 g1 = *((afs_uint32 *)ain);
3471 *com = *((afs_uint32 *)ain);
3472 ain += sizeof(afs_int32);
3473 exporter_type = *((afs_uint32 *)ain); /* In case we support more than NFS */
3476 * Of course, one must be root for most of these functions, but
3477 * we'll allow (for knfs) you to set things if the pag is 0 and
3478 * you're setting tokens or unlogging.
3481 if (!afs_osi_suser(credp)) {
3483 #ifndef AFS_SGI64_ENV
3484 /* Since SGI's suser() returns explicit failure after the call.. */
3488 /* check for acceptable opcodes for normal folks, which are, so far,
3489 * set tokens and unlog.
3491 if (i != 9 && i != 3 && i != 38 && i != 8) {
3492 osi_FreeLargeSpace(inData);
3497 ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3498 ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3499 osi_FreeLargeSpace(inData);
3502 * We map uid 0 to nobody to match the mapping that the nfs
3503 * server does and to ensure that the suser() calls in the afs
3504 * code fails for remote client roots.
3506 uid = afs_nobody; /* NFS_NOBODY == -2 */
3509 #ifdef AFS_AIX41_ENV
3512 newcred->cr_gid = RMTUSER_REQ;
3513 newcred->cr_groups[0] = g0;
3514 newcred->cr_groups[1] = g1;
3516 newcred->cr_ngrps = 2;
3518 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3519 newcred->cr_ngroups = 2;
3521 for (i=2; i<NGROUPS; i++)
3522 newcred->cr_groups[i] = NOGROUP;
3525 #if !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3526 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
3528 if (!(exporter = exporter_find(exporter_type))) {
3529 /* Exporter wasn't initialized or an invalid exporter type */
3533 if (exporter->exp_states & EXP_PWSYNC) {
3534 if (uid != credp->cr_uid) {
3536 return ENOEXEC; /* XXX Find a better errno XXX */
3539 newcred->cr_uid = uid; /* Only temporary */
3540 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3541 /* The client's pag is the only unique identifier for it */
3542 newcred->cr_uid = pag;
3544 if (!code && *com == PSETPAG) {
3545 /* Special case for 'setpag' */
3546 afs_uint32 pagvalue = genpag();
3548 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3550 * Note that we leave the 'outexporter' struct held so it won't
3553 au->exporter = outexporter;
3554 if (ablob->out_size >= 4) {
3555 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3557 afs_PutUser(au, WRITE_LOCK);
3558 if (code) return code;
3559 return PSETPAG; /* Special return for setpag */
3561 EXP_RELE(outexporter);
3564 #endif /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3567 /* get all interface addresses of this client */
3570 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3573 struct vrequest *areq;
3576 afs_int32 *aoutSize;
3578 struct sprefrequest *spin; /* input */
3579 struct sprefinfo *spout; /* output */
3580 struct spref *srvout; /* one output component */
3584 AFS_STATCNT(PGetCPrefs);
3585 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3586 return EIO; /* Inappropriate ioctl for device */
3588 if ( ainSize < sizeof (struct sprefrequest ))
3591 spin = (struct sprefrequest *) ain;
3592 spout = (struct sprefinfo *) aout;
3594 maxNumber = spin->num_servers; /* max addrs this time */
3595 srvout = spout->servers;
3597 ObtainReadLock(&afs_xinterface);
3599 /* copy out the client interface information from the
3600 ** kernel data structure "interface" to the output buffer
3602 for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3603 && ( j< maxNumber) ; i++, j++, srvout++)
3604 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3606 spout->num_servers = j;
3607 *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3609 if ( i >= afs_cb_interface.numberOfInterfaces )
3610 spout->next_offset = 0; /* start from beginning again */
3612 spout->next_offset = spin->offset + j;
3614 ReleaseReadLock(&afs_xinterface);
3619 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3622 struct vrequest *areq;
3625 afs_int32 *aoutSize;
3627 struct setspref *sin;
3630 AFS_STATCNT(PSetCPrefs);
3631 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3632 return EIO; /* Inappropriate ioctl for device */
3634 sin = (struct setspref *)ain;
3636 if ( ainSize < sizeof(struct setspref) )
3638 #if 0 /* num_servers is unsigned */
3639 if ( sin->num_servers < 0 )
3642 if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3645 ObtainWriteLock(&afs_xinterface, 412);
3646 afs_cb_interface.numberOfInterfaces = sin->num_servers;
3647 for ( i=0; (unsigned short)i < sin->num_servers; i++)
3648 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3650 ReleaseWriteLock(&afs_xinterface);
3654 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3657 struct vrequest *areq;
3660 afs_int32 *aoutSize;
3661 struct AFS_UCRED *acred; {
3662 register afs_int32 code;
3663 register struct vcache *tvc;
3664 register struct dcache *tdc;
3665 struct VenusFid tfid;
3667 struct sysname_info sysState;
3668 afs_size_t offset, len;
3670 AFS_STATCNT(PFlushMount);
3671 if (!avc) return EINVAL;
3672 code = afs_VerifyVCache(avc, areq);
3673 if (code) return code;
3674 if (vType(avc) != VDIR) {
3677 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3678 if (!tdc) return ENOENT;
3679 Check_AtSys(avc, ain, &sysState, areq);
3681 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3682 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3683 bufp = sysState.name;
3688 tfid.Cell = avc->fid.Cell;
3689 tfid.Fid.Volume = avc->fid.Fid.Volume;
3690 afs_PutDCache(tdc); /* we're done with the data */
3691 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3692 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3694 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3701 if (vType(tvc) != VLNK) {
3702 afs_PutVCache(tvc, WRITE_LOCK);
3706 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3707 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3709 ObtainWriteLock(&tvc->lock,645);
3710 ObtainWriteLock(&afs_xcbhash, 646);
3711 afs_DequeueCallback(tvc);
3712 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
3713 ReleaseWriteLock(&afs_xcbhash);
3714 /* now find the disk cache entries */
3715 afs_TryToSmush(tvc, acred, 1);
3716 osi_dnlc_purgedp(tvc);
3717 afs_symhint_inval(tvc);
3718 if (tvc->linkData && !(tvc->states & CCore)) {
3719 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3720 tvc->linkData = (char *) 0;
3722 ReleaseWriteLock(&tvc->lock);
3723 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3724 afs_BozonUnlock(&tvc->pvnLock, tvc);
3726 afs_PutVCache(tvc, WRITE_LOCK);
3728 if (sysState.allocked) osi_FreeLargeSpace(bufp);
3732 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3735 struct vrequest *areq;
3738 afs_int32 *aoutSize;
3739 struct AFS_UCRED *acred;
3744 if (!afs_osi_suser(acred)) {
3748 if (ainSize != sizeof(afs_int32)) {
3752 memcpy((char *)&flags, ain, sizeof(afs_int32));
3753 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3757 if (flags & AFSCALL_RXSTATS_ENABLE) {
3758 rx_enableProcessRPCStats();
3760 if (flags & AFSCALL_RXSTATS_DISABLE) {
3761 rx_disableProcessRPCStats();
3763 if (flags & AFSCALL_RXSTATS_CLEAR) {
3764 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3772 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3775 struct vrequest *areq;
3778 afs_int32 *aoutSize;
3779 struct AFS_UCRED *acred;
3784 if (!afs_osi_suser(acred)) {
3788 if (ainSize != sizeof(afs_int32)) {
3792 memcpy((char *)&flags, ain, sizeof(afs_int32));
3793 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3797 if (flags & AFSCALL_RXSTATS_ENABLE) {
3798 rx_enablePeerRPCStats();
3800 if (flags & AFSCALL_RXSTATS_DISABLE) {
3801 rx_disablePeerRPCStats();
3803 if (flags & AFSCALL_RXSTATS_CLEAR) {
3804 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3811 static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
3814 struct vrequest *areq;
3817 afs_int32 *aoutSize; /* set this */
3819 register afs_int32 code, code1;
3822 struct rx_call *tcall;
3823 struct AFSVolSync tsync;
3824 struct AFSFetchStatus OutStatus;
3825 struct AFSCallBack CallBack;
3826 struct VenusFid tfid;
3831 AFS_STATCNT(PSetAcl);
3835 if (ain && (ainSize == 3 * sizeof(afs_int32)))
3836 Fid = (struct AFSFid *) ain;
3838 Fid = &avc->fid.Fid;
3839 tfid.Cell = avc->fid.Cell;
3840 tfid.Fid.Volume = Fid->Volume;
3841 tfid.Fid.Vnode = Fid->Vnode;
3842 tfid.Fid.Unique = Fid->Unique;
3844 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3847 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3848 ICL_TYPE_POINTER, tvc,
3849 ICL_TYPE_FID, &tfid,
3850 ICL_TYPE_FID, &avc->fid);
3853 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3854 ICL_TYPE_POINTER, tvc,
3855 ICL_TYPE_FID, &tfid,
3856 ICL_TYPE_FID, &tvc->fid);
3859 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3862 #ifdef RX_ENABLE_LOCKS
3864 #endif /* RX_ENABLE_LOCKS */
3865 tcall = rx_NewCall(tc->id);
3866 code = StartRXAFS_FetchData(tcall,
3867 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3869 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3870 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3872 code1 = rx_EndCall(tcall, code);
3873 #ifdef RX_ENABLE_LOCKS
3875 #endif /* RX_ENABLE_LOCKS */
3879 (afs_Analyze(tc, code, &tvc->fid, areq,
3880 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3882 /* This call is done only to have the callback things handled correctly */
3883 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3884 afs_PutVCache(tvc, WRITE_LOCK);
3887 *aoutSize = sizeof(afs_int32);
3892 static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
3895 struct vrequest *areq;
3898 afs_int32 *aoutSize; /* set this */
3900 register afs_int32 code;
3903 struct ResidencyCmdInputs *Inputs;
3904 struct ResidencyCmdOutputs *Outputs;
3905 struct VenusFid tfid;
3908 Inputs = (struct ResidencyCmdInputs *) ain;
3909 Outputs = (struct ResidencyCmdOutputs *) aout;
3910 if (!avc) return EINVAL;
3911 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3915 Fid = &avc->fid.Fid;
3917 tfid.Cell = avc->fid.Cell;
3918 tfid.Fid.Volume = Fid->Volume;
3919 tfid.Fid.Vnode = Fid->Vnode;
3920 tfid.Fid.Unique = Fid->Unique;
3922 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3924 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3925 ICL_TYPE_POINTER, tvc,
3926 ICL_TYPE_INT32, Inputs->command,
3927 ICL_TYPE_FID, &tfid);
3931 if (Inputs->command) {
3933 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3935 #ifdef RX_ENABLE_LOCKS
3937 #endif /* RX_ENABLE_LOCKS */
3938 code = RXAFS_ResidencyCmd(tc->id, Fid,
3940 (struct ResidencyCmdOutputs *) aout);
3941 #ifdef RX_ENABLE_LOCKS
3943 #endif /* RX_ENABLE_LOCKS */
3947 (afs_Analyze(tc, code, &tvc->fid, areq,
3948 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3950 /* This call is done to have the callback things handled correctly */
3951 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3952 } else { /* just a status request, return also link data */
3954 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3955 Outputs->chars[0] = 0;
3956 if (vType(tvc) == VLNK) {
3957 ObtainWriteLock(&tvc->lock,555);
3958 if (afs_HandleLink(tvc, areq) == 0)
3959 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3960 ReleaseWriteLock(&tvc->lock);
3964 afs_PutVCache(tvc, WRITE_LOCK);
3967 *aoutSize = sizeof(struct ResidencyCmdOutputs);