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);
1696 ObtainReadLock(&tdc->lock);
1698 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
1699 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1700 ReleaseReadLock(&tdc->lock);
1701 afs_PutDCache(tdc); /* we're done with the data */
1702 bufp = sysState.name;
1706 tfid.Cell = avc->fid.Cell;
1707 tfid.Fid.Volume = avc->fid.Fid.Volume;
1708 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1709 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
1711 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
1718 if (vType(tvc) != VLNK) {
1719 afs_PutVCache(tvc, WRITE_LOCK);
1723 ObtainWriteLock(&tvc->lock,226);
1724 code = afs_HandleLink(tvc, areq);
1726 if (tvc->linkData) {
1727 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1730 /* we have the data */
1731 strcpy(aout, tvc->linkData);
1732 *aoutSize = strlen(tvc->linkData)+1;
1737 ReleaseWriteLock(&tvc->lock);
1738 afs_PutVCache(tvc, WRITE_LOCK);
1740 if (sysState.allocked) osi_FreeLargeSpace(bufp);
1744 static PGetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize)
1747 struct vrequest *areq;
1750 afs_int32 *aoutSize; /* set this */ {
1751 register struct cell *tcell;
1752 register afs_int32 i;
1753 register struct unixuser *tu;
1758 AFS_STATCNT(PGetTokens);
1759 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1760 return EIO; /* Inappropriate ioctl for device */
1762 /* weird interface. If input parameter is present, it is an integer and
1763 we're supposed to return the parm'th tokens for this unix uid.
1764 If not present, we just return tokens for cell 1.
1765 If counter out of bounds, return EDOM.
1766 If no tokens for the particular cell, return ENOTCONN.
1767 Also, if this mysterious parm is present, we return, along with the
1768 tokens, the primary cell indicator (an afs_int32 0) and the cell name
1769 at the end, in that order.
1771 if (newStyle = (ainSize > 0)) {
1772 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1774 i = UHash(areq->uid);
1775 ObtainReadLock(&afs_xuser);
1776 for(tu = afs_users[i]; tu; tu=tu->next) {
1778 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1779 if (iterator-- == 0) break; /* are we done yet? */
1783 if (tu->uid == areq->uid && tu->cell == 1) break;
1788 * No need to hold a read lock on each user entry
1792 ReleaseReadLock(&afs_xuser);
1797 if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1798 tu->states |= (UTokensBad | UNeedsReset);
1799 afs_PutUser(tu, READ_LOCK);
1802 /* use iterator for temp */
1804 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1805 if (iterator < 56) iterator = 56; /* # of bytes we're returning */
1806 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1807 cp += sizeof(afs_int32);
1808 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1810 iterator = sizeof(struct ClearToken);
1811 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1812 cp += sizeof(afs_int32);
1813 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1814 cp += sizeof(struct ClearToken);
1816 /* put out primary id and cell name, too */
1817 iterator = (tu->states & UPrimary ? 1 : 0);
1818 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1819 cp += sizeof(afs_int32);
1820 tcell = afs_GetCell(tu->cell, READ_LOCK);
1822 strcpy(cp, tcell->cellName);
1823 cp += strlen(tcell->cellName)+1;
1824 afs_PutCell(tcell, READ_LOCK);
1828 *aoutSize = cp - aout;
1829 afs_PutUser(tu, READ_LOCK);
1833 static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
1836 struct vrequest *areq;
1839 afs_int32 *aoutSize; /* set this */ {
1840 register afs_int32 i;
1841 register struct unixuser *tu;
1843 AFS_STATCNT(PUnlog);
1844 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1845 return EIO; /* Inappropriate ioctl for device */
1847 i = UHash(areq->uid);
1848 ObtainWriteLock(&afs_xuser,227);
1849 for(tu=afs_users[i]; tu; tu=tu->next) {
1850 if (tu->uid == areq->uid) {
1852 tu->states &= ~UHasTokens;
1853 /* security is not having to say you're sorry */
1854 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
1856 ReleaseWriteLock(&afs_xuser);
1857 /* We have to drop the lock over the call to afs_ResetUserConns, since
1858 * it obtains the afs_xvcache lock. We could also keep the lock, and
1859 * modify ResetUserConns to take parm saying we obtained the lock
1860 * already, but that is overkill. By keeping the "tu" pointer
1861 * held over the released lock, we guarantee that we won't lose our
1862 * place, and that we'll pass over every user conn that existed when
1863 * we began this call.
1865 afs_ResetUserConns(tu);
1867 ObtainWriteLock(&afs_xuser,228);
1869 /* set the expire times to 0, causes
1870 * afs_GCUserData to remove this entry
1872 tu->ct.EndTimestamp = 0;
1874 #endif /* UKERNEL */
1877 ReleaseWriteLock(&afs_xuser);
1881 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1884 struct vrequest *areq;
1887 afs_int32 *aoutSize; /* set this */ {
1888 afs_int32 newHostAddr;
1889 afs_int32 oldHostAddr;
1891 AFS_STATCNT(PMariner);
1893 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost, sizeof(afs_int32));
1895 oldHostAddr = 0xffffffff; /* disabled */
1897 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
1898 if (newHostAddr == 0xffffffff) {
1899 /* disable mariner operations */
1902 else if (newHostAddr) {
1904 afs_marinerHost = newHostAddr;
1906 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
1907 *aoutSize = sizeof(afs_int32);
1911 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1914 struct vrequest *areq;
1917 afs_int32 *aoutSize; /* set this */
1918 struct AFS_UCRED *acred;
1920 register char *cp = 0;
1922 register struct server *ts;
1923 afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1925 struct chservinfo *pcheck;
1927 AFS_STATCNT(PCheckServers);
1929 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1930 return EIO; /* Inappropriate ioctl for device */
1932 if (*lp == 0x12345678) { /* For afs3.3 version */
1933 pcheck=(struct chservinfo *)ain;
1934 if (pcheck->tinterval >= 0) {
1936 memcpy(cp, (char *)&PROBE_INTERVAL, sizeof(afs_int32));
1937 *aoutSize = sizeof(afs_int32);
1938 if (pcheck->tinterval > 0) {
1939 if (!afs_osi_suser(acred))
1941 PROBE_INTERVAL=pcheck->tinterval;
1947 temp=pcheck->tflags;
1948 cp = pcheck->tbuffer;
1949 } else { /* For pre afs3.3 versions */
1950 memcpy((char *)&temp, ain, sizeof(afs_int32));
1951 cp = ain+sizeof(afs_int32);
1952 if (ainSize > sizeof(afs_int32))
1957 * 1: fast check, don't contact servers.
1958 * 2: local cell only.
1961 /* have cell name, too */
1962 cellp = afs_GetCellByName(cp, READ_LOCK);
1963 if (!cellp) return ENOENT;
1965 else cellp = (struct cell *) 0;
1966 if (!cellp && (temp & 2)) {
1967 /* use local cell */
1968 cellp = afs_GetCell(1, READ_LOCK);
1970 if (!(temp & 1)) { /* if not fast, call server checker routine */
1971 afs_CheckServers(1, cellp); /* check down servers */
1972 afs_CheckServers(0, cellp); /* check up servers */
1974 /* now return the current down server list */
1976 ObtainReadLock(&afs_xserver);
1977 for(i=0;i<NSERVERS;i++) {
1978 for(ts = afs_servers[i]; ts; ts=ts->next) {
1979 if (cellp && ts->cell != cellp) continue; /* cell spec'd and wrong */
1980 if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1981 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
1982 cp += sizeof(afs_int32);
1986 ReleaseReadLock(&afs_xserver);
1987 if (cellp) afs_PutCell(cellp, READ_LOCK);
1988 *aoutSize = cp - aout;
1992 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
1995 struct vrequest *areq;
1998 afs_int32 *aoutSize; /* set this */ {
1999 AFS_STATCNT(PCheckVolNames);
2000 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2001 return EIO; /* Inappropriate ioctl for device */
2003 afs_CheckRootVolume();
2004 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
2005 AFS_VOLCHECK_EXPIRED |
2007 AFS_VOLCHECK_MTPTS);
2011 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
2014 struct vrequest *areq;
2017 afs_int32 *aoutSize; /* set this */ {
2021 struct unixuser *tu;
2023 extern afs_rwlock_t afs_xsrvAddr;
2025 AFS_STATCNT(PCheckAuth);
2026 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2027 return EIO; /* Inappropriate ioctl for device */
2030 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2031 if (!tu) retValue = EACCES;
2033 /* we have a user */
2034 ObtainReadLock(&afs_xsrvAddr);
2035 ObtainReadLock(&afs_xconn);
2037 /* any tokens set? */
2038 if ((tu->states & UHasTokens) == 0) retValue = EACCES;
2039 /* all connections in cell 1 working? */
2040 for(i=0;i<NSERVERS;i++) {
2041 for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
2042 for (tc = sa->conns; tc; tc=tc->next) {
2043 if (tc->user == tu && (tu->states & UTokensBad))
2048 ReleaseReadLock(&afs_xsrvAddr);
2049 ReleaseReadLock(&afs_xconn);
2050 afs_PutUser(tu, READ_LOCK);
2052 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2053 *aoutSize = sizeof(afs_int32);
2057 static Prefetch(apath, adata, afollow, acred)
2059 struct afs_ioctl *adata;
2061 struct AFS_UCRED *acred;
2064 register afs_int32 code;
2065 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2071 AFS_STATCNT(Prefetch);
2072 if (!apath) return EINVAL;
2073 tp = osi_AllocLargeSpace(1024);
2074 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2076 osi_FreeLargeSpace(tp);
2079 if (afs_BBusy()) { /* do this as late as possible */
2080 osi_FreeLargeSpace(tp);
2081 return EWOULDBLOCK; /* pretty close */
2083 afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred,
2084 (afs_size_t) 0, (afs_size_t) 0, tp);
2088 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
2091 struct vrequest *areq;
2094 afs_int32 *aoutSize; /* set this */ {
2095 register struct volume *tvp;
2096 register struct server *ts;
2097 register afs_int32 i;
2100 AFS_STATCNT(PFindVolume);
2101 if (!avc) return EINVAL;
2102 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
2105 for(i=0;i<MAXHOSTS;i++) {
2106 ts = tvp->serverHost[i];
2108 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2109 cp += sizeof(afs_int32);
2112 /* still room for terminating NULL, add it on */
2113 ainSize = 0; /* reuse vbl */
2114 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2115 cp += sizeof(afs_int32);
2117 *aoutSize = cp - aout;
2118 afs_PutVolume(tvp, READ_LOCK);
2124 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
2127 struct vrequest *areq;
2130 afs_int32 *aoutSize; /* set this */ {
2131 register afs_int32 code;
2134 AFS_STATCNT(PViceAccess);
2135 if (!avc) return EINVAL;
2136 code = afs_VerifyVCache(avc, areq);
2137 if (code) return code;
2138 memcpy((char *)&temp, ain, sizeof(afs_int32));
2139 code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2144 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2147 struct vrequest *areq;
2150 afs_int32 *aoutSize; /* set this */
2151 struct AFS_UCRED *acred;
2156 AFS_STATCNT(PSetCacheSize);
2157 if (!afs_osi_suser(acred))
2159 /* too many things are setup initially in mem cache version */
2160 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2161 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2162 if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2164 extern u_int afs_min_cache;
2165 if (newValue < afs_min_cache)
2166 afs_cacheBlocks = afs_min_cache;
2168 afs_cacheBlocks = newValue;
2170 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2171 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2172 afs_MaybeWakeupTruncateDaemon();
2173 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2174 afs_osi_Wait(1000, 0, 0);
2175 afs_MaybeWakeupTruncateDaemon();
2180 #define MAXGCSTATS 16
2181 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2184 struct vrequest *areq;
2187 afs_int32 *aoutSize; /* set this */ {
2188 afs_int32 results[MAXGCSTATS];
2190 AFS_STATCNT(PGetCacheSize);
2191 memset((char *)results, 0, sizeof(results));
2192 results[0] = afs_cacheBlocks;
2193 results[1] = afs_blocksUsed;
2194 memcpy(aout, (char *)results, sizeof(results));
2195 *aoutSize = sizeof(results);
2199 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2202 struct vrequest *areq;
2205 afs_int32 *aoutSize; /* set this */ {
2206 register struct conn *tc;
2207 register afs_int32 code;
2208 struct AFSCallBack CallBacks_Array[1];
2209 struct AFSCBFids theFids;
2210 struct AFSCBs theCBs;
2213 AFS_STATCNT(PRemoveCallBack);
2214 if (!avc) return EINVAL;
2215 if (avc->states & CRO) return 0; /* read-only-ness can't change */
2216 ObtainWriteLock(&avc->lock,229);
2217 theFids.AFSCBFids_len = 1;
2218 theCBs.AFSCBs_len = 1;
2219 theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2220 theCBs.AFSCBs_val = CallBacks_Array;
2221 CallBacks_Array[0].CallBackType = CB_DROPPED;
2222 if (avc->callback) {
2224 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2226 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2227 #ifdef RX_ENABLE_LOCKS
2229 #endif /* RX_ENABLE_LOCKS */
2230 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2231 #ifdef RX_ENABLE_LOCKS
2233 #endif /* RX_ENABLE_LOCKS */
2236 /* don't set code on failure since we wouldn't use it */
2238 (afs_Analyze(tc, code, &avc->fid, areq,
2239 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2240 SHARED_LOCK, (struct cell *)0));
2242 ObtainWriteLock(&afs_xcbhash, 457);
2243 afs_DequeueCallback(avc);
2245 avc->states &= ~(CStatd | CUnique);
2246 ReleaseWriteLock(&afs_xcbhash);
2247 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2248 osi_dnlc_purgedp(avc);
2250 ReleaseWriteLock(&avc->lock);
2254 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2257 struct vrequest *areq;
2261 struct AFS_UCRED *acred;
2262 afs_int32 *aoutSize; /* set this */ {
2263 /* create a new cell */
2264 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2265 register struct cell *tcell;
2266 char *newcell=0, *linkedcell=0, *tp= ain;
2267 register afs_int32 code, linkedstate=0, ls;
2268 u_short fsport = 0, vlport = 0;
2271 AFS_STATCNT(PNewCell);
2272 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2273 return EIO; /* Inappropriate ioctl for device */
2275 if (!afs_osi_suser(acred))
2278 memcpy((char *)&magic, tp, sizeof(afs_int32));
2279 tp += sizeof(afs_int32);
2280 if (magic != 0x12345678)
2283 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2284 * server addresses while the 3.5 fs newcell command passes
2285 * MAXHOSTS. To figure out which is which, check if the cellname
2288 newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2289 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2291 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2292 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2293 tp += (scount * sizeof(afs_int32));
2295 lp = (afs_int32 *)tp;
2298 if (fsport < 1024) fsport = 0; /* Privileged ports not allowed */
2299 if (vlport < 1024) vlport = 0; /* Privileged ports not allowed */
2300 tp += (3 * sizeof(afs_int32));
2302 if ((ls = *lp) & 1) {
2303 linkedcell = tp + strlen(newcell)+1;
2304 linkedstate |= CLinkedCell;
2307 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2308 code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0, (char *) 0);
2312 static PNewAlias(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2315 struct vrequest *areq;
2319 struct AFS_UCRED *acred;
2320 afs_int32 *aoutSize; /* set this */
2322 /* create a new cell alias */
2323 register struct cell *tcell;
2325 register afs_int32 code;
2326 char *realName, *aliasName;
2327 register struct afs_q *cq, *tq;
2329 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2330 return EIO; /* Inappropriate ioctl for device */
2332 if (!afs_osi_suser(acred))
2336 tp += strlen(aliasName) + 1;
2340 * Prevent user from shooting themselves in the foot -- don't allow
2341 * creation of aliases when a real cell already exists with that name.
2343 ObtainReadLock(&afs_xcell);
2344 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2345 tcell = QTOC(cq); tq = QNext(cq);
2346 if ((afs_strcasecmp(tcell->cellName, aliasName) == 0) &&
2347 !(tcell->states & CAlias)) {
2348 ReleaseReadLock(&afs_xcell);
2352 ReleaseReadLock(&afs_xcell);
2354 code = afs_NewCell(aliasName, 0, CAlias, 0, 0, 0, 0, realName);
2359 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2362 struct vrequest *areq;
2365 afs_int32 *aoutSize; /* set this */ {
2366 afs_int32 whichCell;
2367 register struct cell *tcell=0;
2368 register afs_int32 i;
2369 register char *cp, *tp = ain;
2370 register struct afs_q *cq, *tq;
2372 AFS_STATCNT(PListCells);
2373 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2374 return EIO; /* Inappropriate ioctl for device */
2376 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2377 tp += sizeof(afs_int32);
2378 ObtainReadLock(&afs_xcell);
2379 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2380 tcell = QTOC(cq); tq = QNext(cq);
2381 if (tcell->states & CAlias) {
2385 if (whichCell == 0) break;
2391 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2392 for(i=0;i<MAXCELLHOSTS;i++) {
2393 if (tcell->cellHosts[i] == 0) break;
2394 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip, sizeof(afs_int32));
2395 cp += sizeof(afs_int32);
2397 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2398 strcpy(cp, tcell->cellName);
2399 cp += strlen(tcell->cellName)+1;
2400 *aoutSize = cp - aout;
2402 ReleaseReadLock(&afs_xcell);
2403 if (tcell) return 0;
2407 static PListAliases(avc, afun, areq, ain, aout, ainSize, aoutSize)
2410 struct vrequest *areq;
2413 afs_int32 *aoutSize; /* set this */
2415 afs_int32 whichAlias;
2416 register struct cell *tcell=0;
2417 register char *cp, *tp = ain;
2418 register struct afs_q *cq, *tq;
2420 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2421 return EIO; /* Inappropriate ioctl for device */
2422 if (ainSize < sizeof(afs_int32))
2425 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2426 tp += sizeof(afs_int32);
2428 ObtainReadLock(&afs_xcell);
2429 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2430 tcell = QTOC(cq); tq = QNext(cq);
2431 if (!(tcell->states & CAlias)) {
2435 if (whichAlias == 0) break;
2441 strcpy(cp, tcell->cellName);
2442 cp += strlen(tcell->cellName)+1;
2443 strcpy(cp, tcell->realName);
2444 cp += strlen(tcell->realName)+1;
2445 *aoutSize = cp - aout;
2447 ReleaseReadLock(&afs_xcell);
2448 if (tcell) return 0;
2452 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2455 struct vrequest *areq;
2459 afs_int32 *aoutSize; /* set this */ {
2460 register afs_int32 code;
2462 struct sysname_info sysState;
2463 afs_size_t offset, len;
2464 register struct conn *tc;
2465 register struct dcache *tdc;
2466 register struct vcache *tvc;
2467 struct AFSFetchStatus OutDirStatus;
2468 struct VenusFid tfid;
2469 struct AFSVolSync tsync;
2473 /* "ain" is the name of the file in this dir to remove */
2475 AFS_STATCNT(PRemoveMount);
2476 if (!avc) return EINVAL;
2477 code = afs_VerifyVCache(avc, areq);
2478 if (code) return code;
2479 if (vType(avc) != VDIR) return ENOTDIR;
2481 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2482 if (!tdc) return ENOENT;
2483 Check_AtSys(avc, ain, &sysState, areq);
2484 ObtainReadLock(&tdc->lock);
2486 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
2487 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2488 ReleaseReadLock(&tdc->lock);
2489 bufp = sysState.name;
2494 tfid.Cell = avc->fid.Cell;
2495 tfid.Fid.Volume = avc->fid.Fid.Volume;
2496 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2497 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2499 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2500 (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2507 if (vType(tvc) != VLNK) {
2509 afs_PutVCache(tvc, WRITE_LOCK);
2513 ObtainWriteLock(&tvc->lock,230);
2514 code = afs_HandleLink(tvc, areq);
2516 if (tvc->linkData) {
2517 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2522 ReleaseWriteLock(&tvc->lock);
2523 osi_dnlc_purgedp(tvc);
2524 afs_PutVCache(tvc, WRITE_LOCK);
2529 ObtainWriteLock(&avc->lock,231);
2530 osi_dnlc_remove(avc, bufp, tvc);
2532 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2534 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2536 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2537 bufp, &OutDirStatus, &tsync);
2543 (afs_Analyze(tc, code, &avc->fid, areq,
2544 AFS_STATS_FS_RPCIDX_REMOVEFILE,
2545 SHARED_LOCK, (struct cell *)0));
2548 if (tdc) afs_PutDCache(tdc);
2549 ReleaseWriteLock(&avc->lock);
2553 /* we have the thing in the cache */
2554 ObtainWriteLock(&tdc->lock, 661);
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 ReleaseWriteLock(&tdc->lock);
2564 afs_PutDCache(tdc); /* drop ref count */
2566 avc->states &= ~CUnique; /* For the dfs xlator */
2567 ReleaseWriteLock(&avc->lock);
2570 if (sysState.allocked) osi_FreeLargeSpace(bufp);
2574 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2577 struct vrequest *areq;
2581 struct AFS_UCRED *acred;
2582 afs_int32 *aoutSize; /* set this */ {
2583 return EINVAL; /* OBSOLETE */
2586 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2589 struct vrequest *areq;
2592 afs_int32 *aoutSize; /* set this */ {
2593 register struct cell *tcell;
2596 AFS_STATCNT(PGetCellStatus);
2597 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2598 return EIO; /* Inappropriate ioctl for device */
2600 tcell = afs_GetCellByName(ain, READ_LOCK);
2601 if (!tcell) return ENOENT;
2602 temp = tcell->states;
2603 afs_PutCell(tcell, READ_LOCK);
2604 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2605 *aoutSize = sizeof(afs_int32);
2609 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2612 struct vrequest *areq;
2615 struct AFS_UCRED *acred;
2616 afs_int32 *aoutSize; /* set this */ {
2617 register struct cell *tcell;
2620 if (!afs_osi_suser(acred))
2622 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2623 return EIO; /* Inappropriate ioctl for device */
2625 tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2626 if (!tcell) return ENOENT;
2627 memcpy((char *)&temp, ain, sizeof(afs_int32));
2629 tcell->states |= CNoSUID;
2631 tcell->states &= ~CNoSUID;
2632 afs_PutCell(tcell, WRITE_LOCK);
2636 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2639 struct vrequest *areq;
2642 afs_int32 *aoutSize; /* set this */
2643 struct AFS_UCRED *acred;
2645 extern struct volume *afs_volumes[NVOLS];
2646 register afs_int32 i;
2647 register struct dcache *tdc;
2648 register struct vcache *tvc;
2649 register struct volume *tv;
2650 afs_int32 cell, volume;
2652 AFS_STATCNT(PFlushVolumeData);
2655 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2656 return EIO; /* Inappropriate ioctl for device */
2658 volume = avc->fid.Fid.Volume; /* who to zap */
2659 cell = avc->fid.Cell;
2662 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2663 * the vcaches associated with the volume.
2665 ObtainReadLock(&afs_xvcache);
2666 for(i = 0; i < VCSIZE; i++) {
2667 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2668 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2669 #if defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
2670 VN_HOLD((struct vnode *)tvc);
2672 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2678 ReleaseReadLock(&afs_xvcache);
2679 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2680 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
2682 ObtainWriteLock(&tvc->lock,232);
2684 ObtainWriteLock(&afs_xcbhash, 458);
2685 afs_DequeueCallback(tvc);
2686 tvc->states &= ~(CStatd | CDirty);
2687 ReleaseWriteLock(&afs_xcbhash);
2688 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2689 osi_dnlc_purgedp(tvc);
2690 afs_TryToSmush(tvc, acred, 1);
2691 ReleaseWriteLock(&tvc->lock);
2692 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2693 afs_BozonUnlock(&tvc->pvnLock, tvc);
2695 ObtainReadLock(&afs_xvcache);
2696 /* our tvc ptr is still good until now */
2701 ReleaseReadLock(&afs_xvcache);
2704 MObtainWriteLock(&afs_xdcache,328); /* needed if you're going to flush any stuff */
2705 for(i=0;i<afs_cacheFiles;i++) {
2706 if (!(afs_indexFlags[i] & IFEverUsed)) continue; /* never had any data */
2707 tdc = afs_GetDSlot(i, (struct dcache *) 0);
2708 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
2709 ReleaseReadLock(&tdc->tlock);
2710 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2711 if (! (afs_indexFlags[i] & IFDataMod)) {
2712 /* if the file is modified, but has a ref cnt of only 1, then
2713 someone probably has the file open and is writing into it.
2714 Better to skip flushing such a file, it will be brought back
2715 immediately on the next write anyway.
2717 If we *must* flush, then this code has to be rearranged to call
2718 afs_storeAllSegments() first */
2719 afs_FlushDCache(tdc);
2723 ReleaseReadLock(&tdc->tlock);
2725 afs_PutDCache(tdc); /* bumped by getdslot */
2727 MReleaseWriteLock(&afs_xdcache);
2729 ObtainReadLock(&afs_xvolume);
2730 for (i=0;i<NVOLS;i++) {
2731 for (tv = afs_volumes[i]; tv; tv=tv->next) {
2732 if (tv->volume == volume) {
2733 afs_ResetVolumeInfo(tv);
2738 ReleaseReadLock(&afs_xvolume);
2740 /* probably, a user is doing this, probably, because things are screwed up.
2741 * maybe it's the dnlc's fault? */
2748 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2751 struct vrequest *areq;
2754 afs_int32 *aoutSize; /* set this */ {
2755 register afs_int32 code;
2756 struct vcxstat stat;
2759 /* AFS_STATCNT(PGetVnodeXStatus); */
2760 if (!avc) return EINVAL;
2761 code = afs_VerifyVCache(avc, areq);
2762 if (code) return code;
2763 if (vType(avc) == VDIR)
2764 mode = PRSFS_LOOKUP;
2767 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2769 stat.fid = avc->fid;
2770 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2771 stat.lock = avc->lock;
2772 stat.parentVnode = avc->parentVnode;
2773 stat.parentUnique = avc->parentUnique;
2774 hset(stat.flushDV, avc->flushDV);
2775 hset(stat.mapDV, avc->mapDV);
2776 stat.truncPos = avc->truncPos;
2777 { /* just grab the first two - won't break anything... */
2778 struct axscache *ac;
2780 for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2781 stat.randomUid[i] = ac->uid;
2782 stat.randomAccess[i] = ac->axess;
2785 stat.callback = afs_data_pointer_to_int32(avc->callback);
2786 stat.cbExpires = avc->cbExpires;
2787 stat.anyAccess = avc->anyAccess;
2788 stat.opens = avc->opens;
2789 stat.execsOrWriters = avc->execsOrWriters;
2790 stat.flockCount = avc->flockCount;
2791 stat.mvstat = avc->mvstat;
2792 stat.states = avc->states;
2793 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
2794 *aoutSize = sizeof(struct vcxstat);
2799 /* We require root for local sysname changes, but not for remote */
2800 /* (since we don't really believe remote uids anyway) */
2801 /* outname[] shouldn't really be needed- this is left as an excercise */
2802 /* for the reader. */
2803 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2806 struct vrequest *areq;
2809 afs_int32 *aoutSize; /* set this */
2810 register struct AFS_UCRED *acred;
2812 char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2813 int setsysname, foundname=0;
2814 register struct afs_exporter *exporter;
2815 extern struct unixuser *afs_FindUser();
2816 extern char *afs_sysname;
2817 extern char *afs_sysnamelist[];
2818 extern int afs_sysnamecount;
2819 register struct unixuser *au;
2820 register afs_int32 pag, error;
2824 AFS_STATCNT(PSetSysName);
2825 if (!afs_globalVFS) {
2826 /* Afsd is NOT running; disable it */
2827 #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)
2830 return (setuerror(EINVAL), EINVAL);
2833 memset(inname, 0, MAXSYSNAME);
2834 memcpy((char *)&setsysname, ain, sizeof(afs_int32));
2835 ain += sizeof(afs_int32);
2839 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
2841 for(cp = ain,count = 0;count < setsysname;count++) {
2842 /* won't go past end of ain since maxsysname*num < ain length */
2844 if (t >= MAXSYSNAME || t <= 0)
2846 /* check for names that can shoot us in the foot */
2847 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
2853 /* inname gets first entry in case we're being a translater */
2855 memcpy(inname, ain, t+1); /* include terminating null */
2858 if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2859 pag = PagInCred(acred);
2861 return EINVAL; /* Better than panicing */
2863 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2864 return EINVAL; /* Better than panicing */
2866 if (!(exporter = au->exporter)) {
2867 afs_PutUser(au, READ_LOCK);
2868 return EINVAL; /* Better than panicing */
2870 error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2872 if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2874 afs_PutUser(au, READ_LOCK);
2879 afs_PutUser(au, READ_LOCK);
2882 /* Not xlating, so local case */
2883 if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2884 if (!setsysname) { /* user just wants the info */
2885 strcpy(outname, afs_sysname);
2886 foundname = afs_sysnamecount;
2887 } else { /* Local guy; only root can change sysname */
2888 if (!afs_osi_suser(acred))
2891 /* clear @sys entries from the dnlc, once afs_lookup can
2892 do lookups of @sys entries and thinks it can trust them */
2893 /* privs ok, store the entry, ... */
2894 strcpy(afs_sysname, inname);
2895 if (setsysname > 1) { /* ... or list */
2897 for(count=1; count < setsysname;++count) {
2898 if (!afs_sysnamelist[count])
2899 osi_Panic("PSetSysName: no afs_sysnamelist entry to write\n");
2901 memcpy(afs_sysnamelist[count], cp, t+1); /* include null */
2905 afs_sysnamecount = setsysname;
2909 cp = aout; /* not changing so report back the count and ... */
2910 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
2911 cp += sizeof(afs_int32);
2913 strcpy(cp, outname); /* ... the entry, ... */
2914 cp += strlen(outname)+1;
2915 for(count=1; count < foundname; ++count) { /* ... or list. */
2916 /* Note: we don't support @sys lists for exporters */
2917 if (!afs_sysnamelist[count])
2918 osi_Panic("PSetSysName: no afs_sysnamelist entry to read\n");
2919 t = strlen(afs_sysnamelist[count]);
2920 if (t >= MAXSYSNAME)
2921 osi_Panic("PSetSysName: sysname entry garbled\n");
2922 strcpy(cp, afs_sysnamelist[count]);
2926 *aoutSize = cp - aout;
2931 /* sequential search through the list of touched cells is not a good
2932 * long-term solution here. For small n, though, it should be just
2933 * fine. Should consider special-casing the local cell for large n.
2934 * Likewise for PSetSPrefs.
2936 static void ReSortCells(s,l, vlonly)
2937 int s; /* number of ids in array l[] -- NOT index of last id */
2938 afs_int32 l[]; /* array of cell ids which have volumes that need to be sorted */
2939 int vlonly; /* sort vl servers or file servers?*/
2941 extern struct volume *afs_volumes[NVOLS]; /* volume hash table */
2949 ObtainWriteLock(&afs_xcell,300);
2951 tcell = afs_GetCellNoLock(l[k], WRITE_LOCK);
2952 if (!tcell) continue;
2953 afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2954 afs_PutCell(tcell, WRITE_LOCK);
2956 ReleaseWriteLock(&afs_xcell);
2960 ObtainReadLock(&afs_xvolume);
2961 for (i= 0; i< NVOLS; i++) {
2962 for (j=afs_volumes[i];j;j=j->next) {
2964 if (j->cell == l[k]) {
2965 ObtainWriteLock(&j->lock,233);
2966 afs_SortServers(j->serverHost, MAXHOSTS);
2967 ReleaseWriteLock(&j->lock);
2972 ReleaseReadLock(&afs_xvolume);
2977 static int afs_setsprefs(sp, num, vlonly)
2980 unsigned int vlonly;
2983 int i,j,k,matches,touchedSize;
2984 struct server *srvr = NULL;
2985 afs_int32 touched[34];
2989 for (k=0; k < num; sp++, k++) {
2991 printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2994 ObtainReadLock(&afs_xserver);
2996 i = SHash(sp->host.s_addr);
2997 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2998 if (sa->sa_ip == sp->host.s_addr) {
3000 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3001 || (sa->sa_portal == AFS_FSPORT);
3002 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3009 if (sa && matches) { /* found one! */
3011 printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
3013 sa->sa_iprank = sp->rank + afs_randomMod15();
3014 afs_SortOneServer(sa->server);
3017 /* if we don't know yet what cell it's in, this is moot */
3018 for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
3019 /* is it in our list of touched cells ? */ ;
3020 if (j < 0) { /* no, it's not */
3021 touched[touchedSize++] = srvr->cell->cell;
3022 if (touchedSize >= 32) { /* watch for ovrflow */
3023 ReleaseReadLock(&afs_xserver);
3024 ReSortCells(touchedSize, touched, vlonly);
3026 ObtainReadLock(&afs_xserver);
3032 ReleaseReadLock(&afs_xserver);
3033 /* if we didn't find one, start to create one. */
3034 /* Note that it doesn't have a cell yet... */
3036 afs_uint32 temp = sp->host.s_addr;
3037 srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3038 WRITE_LOCK, (afsUUID *)0,0);
3039 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3040 afs_PutServer(srvr, WRITE_LOCK);
3042 } /* for all cited preferences */
3044 ReSortCells(touchedSize, touched, vlonly);
3048 /* Note that this may only be performed by the local root user.
3051 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3054 struct vrequest *areq;
3057 struct AFS_UCRED *acred;
3058 afs_int32 *aoutSize;
3060 struct setspref *ssp;
3061 AFS_STATCNT(PSetSPrefs);
3063 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3064 return EIO; /* Inappropriate ioctl for device */
3066 if (!afs_osi_suser(acred))
3069 if (ainSize < sizeof(struct setspref))
3072 ssp = (struct setspref *)ain;
3073 if (ainSize < sizeof(struct spref)*ssp->num_servers)
3076 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3077 (ssp->flags & DBservers));
3082 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3085 struct vrequest *areq;
3088 struct AFS_UCRED *acred;
3089 afs_int32 *aoutSize;
3092 AFS_STATCNT(PSetSPrefs);
3093 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3094 return EIO; /* Inappropriate ioctl for device */
3097 if (!afs_osi_suser(acred))
3100 sp = (struct spref *)ain;
3101 afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
3105 /* some notes on the following code...
3106 * in the hash table of server structs, all servers with the same IP address
3107 * will be on the same overflow chain.
3108 * This could be sped slightly in some circumstances by having it cache the
3109 * immediately previous slot in the hash table and some supporting information
3110 * Only reports file servers now.
3113 PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3116 struct vrequest *areq;
3119 afs_int32 *aoutSize;
3121 struct sprefrequest *spin; /* input */
3122 struct sprefinfo *spout; /* output */
3123 struct spref *srvout; /* one output component */
3124 int i,j; /* counters for hash table traversal */
3125 struct server *srvr; /* one of CM's server structs */
3128 int vlonly; /* just return vlservers ? */
3131 AFS_STATCNT(PGetSPrefs);
3132 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3133 return EIO; /* Inappropriate ioctl for device */
3136 if (ainSize < sizeof (struct sprefrequest_33)) {
3140 spin = ((struct sprefrequest *) ain);
3143 if (ainSize > sizeof (struct sprefrequest_33)) {
3144 vlonly = (spin->flags & DBservers);
3148 /* struct sprefinfo includes 1 server struct... that size gets added
3149 * in during the loop that follows.
3151 *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
3152 spout = (struct sprefinfo *) aout;
3153 spout->next_offset = spin->offset;
3154 spout->num_servers = 0;
3155 srvout = spout->servers;
3157 ObtainReadLock(&afs_xserver);
3158 for (i=0, j=0; j < NSERVERS; j++) { /* sift through hash table */
3159 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3160 if (spin->offset > (unsigned short)i) {
3161 continue; /* catch up to where we left off */
3163 spout->next_offset++;
3166 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3167 || (sa->sa_portal == AFS_FSPORT);
3169 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3170 /* only report ranks for vl servers */
3174 srvout->host.s_addr = sa->sa_ip;
3175 srvout->rank = sa->sa_iprank;
3176 *aoutSize += sizeof(struct spref);
3177 spout->num_servers++;
3180 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3181 ReleaseReadLock(&afs_xserver); /* no more room! */
3186 ReleaseReadLock(&afs_xserver);
3188 spout->next_offset = 0; /* start over from the beginning next time */
3192 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3193 int afs_NFSRootOnly = 1;
3194 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3197 struct vrequest *areq;
3200 afs_int32 *aoutSize; /* set this */
3201 struct AFS_UCRED *acred;
3203 afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
3204 extern struct afs_exporter *exporter_find();
3205 register struct afs_exporter *exporter;
3207 AFS_STATCNT(PExportAfs);
3208 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3209 type = handleValue >> 24;
3214 exporter = exporter_find(type);
3216 export = handleValue & 3;
3217 changestate = handleValue & 0xff;
3218 smounts = (handleValue >> 2) & 3;
3219 pwsync = (handleValue >> 4) & 3;
3220 convmode = (handleValue >> 6) & 3;
3222 changestate = (handleValue >> 16) & 0x1;
3223 convmode = (handleValue >> 16) & 0x2;
3224 pwsync = (handleValue >> 16) & 0x4;
3225 smounts = (handleValue >> 16) & 0x8;
3226 export = handleValue & 0xff;
3229 /* Failed finding desired exporter; */
3233 handleValue = exporter->exp_states;
3234 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3235 *aoutSize = sizeof(afs_int32);
3237 if (!afs_osi_suser(acred))
3238 return EACCES; /* Only superuser can do this */
3242 exporter->exp_states |= EXP_EXPORTED;
3244 exporter->exp_states &= ~EXP_EXPORTED;
3248 exporter->exp_states |= EXP_UNIXMODE;
3250 exporter->exp_states &= ~EXP_UNIXMODE;
3254 exporter->exp_states |= EXP_PWSYNC;
3256 exporter->exp_states &= ~EXP_PWSYNC;
3260 afs_NFSRootOnly = 0;
3261 exporter->exp_states |= EXP_SUBMOUNTS;
3263 afs_NFSRootOnly = 1;
3264 exporter->exp_states &= ~EXP_SUBMOUNTS;
3267 handleValue = exporter->exp_states;
3268 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3269 *aoutSize = sizeof(afs_int32);
3272 exporter->exp_states |= EXP_EXPORTED;
3274 exporter->exp_states &= ~EXP_EXPORTED;
3276 exporter->exp_states |= EXP_UNIXMODE;
3278 exporter->exp_states &= ~EXP_UNIXMODE;
3280 exporter->exp_states |= EXP_PWSYNC;
3282 exporter->exp_states &= ~EXP_PWSYNC;
3284 afs_NFSRootOnly = 0;
3285 exporter->exp_states |= EXP_SUBMOUNTS;
3287 afs_NFSRootOnly = 1;
3288 exporter->exp_states &= ~EXP_SUBMOUNTS;
3297 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3300 struct vrequest *areq;
3303 struct AFS_UCRED *acred;
3304 afs_int32 *aoutSize; /* set this */
3306 struct gaginfo *gagflags;
3308 if (!afs_osi_suser(acred))
3311 gagflags = (struct gaginfo *) ain;
3312 afs_showflags = gagflags->showflags;
3319 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3322 struct vrequest *areq;
3325 struct AFS_UCRED *acred;
3326 afs_int32 *aoutSize;
3328 struct rxparams *rxp;
3330 if (!afs_osi_suser(acred))
3333 rxp = (struct rxparams *) ain;
3335 if (rxp->rx_initReceiveWindow)
3336 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3337 if (rxp->rx_maxReceiveWindow)
3338 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3339 if (rxp->rx_initSendWindow)
3340 rx_initSendWindow = rxp->rx_initSendWindow;
3341 if (rxp->rx_maxSendWindow)
3342 rx_maxSendWindow = rxp->rx_maxSendWindow;
3343 if (rxp->rxi_nSendFrags)
3344 rxi_nSendFrags = rxp->rxi_nSendFrags;
3345 if (rxp->rxi_nRecvFrags)
3346 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3347 if (rxp->rxi_OrphanFragSize)
3348 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3349 if (rxp->rx_maxReceiveSize)
3351 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3352 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3354 if (rxp->rx_MyMaxSendSize)
3355 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3360 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3363 struct vrequest *areq;
3367 afs_int32 *aoutSize; /* set this */
3369 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3372 memcpy(aout, (char*)&cm_initParams, sizeof(struct cm_initparams));
3373 *aoutSize = sizeof(struct cm_initparams);
3377 #ifdef AFS_SGI65_ENV
3378 /* They took crget() from us, so fake it. */
3379 static cred_t *crget(void)
3382 cr = crdup(get_current_cred());
3383 memset((char*)cr, 0, sizeof(cred_t));
3384 #if CELL || CELL_PREPARE
3392 PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3395 struct vrequest *areq;
3398 afs_int32 *aoutSize;
3399 struct AFS_UCRED *acred;
3401 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3402 *aoutSize=sizeof(afs_int32);
3407 PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3410 struct vrequest *areq;
3413 afs_int32 *aoutSize;
3414 struct AFS_UCRED *acred;
3418 if (!afs_osi_suser(acred))
3420 if (ainSize != sizeof(afs_int32) || ain == NULL)
3422 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3423 /* if new mappings added later this will need to be changed */
3424 if (tmpval != 0 && tmpval != 1)
3431 * Create new credentials to correspond to a remote user with given
3432 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3433 * provide pioctl (and other) services to foreign clients (i.e. nfs
3434 * clients) by using this call to `become' the client.
3437 #define PIOCTL_HEADER 6
3438 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3441 afs_uint32 hostaddr;
3442 afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3443 extern struct afs_exporter *exporter_find();
3444 struct afs_exporter *exporter, *outexporter;
3445 struct AFS_UCRED *newcred;
3446 struct unixuser *au;
3448 #if defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3449 return EINVAL; /* NFS trans not supported for Ultrix */
3451 #if defined(AFS_SGIMP_ENV)
3452 osi_Assert(ISAFS_GLOCK());
3454 AFS_STATCNT(HandleClientContext);
3455 if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) {
3456 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3457 return EINVAL; /* Too small to be good */
3459 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3460 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3462 osi_FreeLargeSpace(inData);
3466 /* Extract information for remote user */
3467 hostaddr = *((afs_uint32 *)ain);
3468 ain += sizeof(hostaddr);
3469 uid = *((afs_uint32 *)ain);
3471 g0 = *((afs_uint32 *)ain);
3473 g1 = *((afs_uint32 *)ain);
3475 *com = *((afs_uint32 *)ain);
3476 ain += sizeof(afs_int32);
3477 exporter_type = *((afs_uint32 *)ain); /* In case we support more than NFS */
3480 * Of course, one must be root for most of these functions, but
3481 * we'll allow (for knfs) you to set things if the pag is 0 and
3482 * you're setting tokens or unlogging.
3485 if (!afs_osi_suser(credp)) {
3487 #ifndef AFS_SGI64_ENV
3488 /* Since SGI's suser() returns explicit failure after the call.. */
3492 /* check for acceptable opcodes for normal folks, which are, so far,
3493 * set tokens and unlog.
3495 if (i != 9 && i != 3 && i != 38 && i != 8) {
3496 osi_FreeLargeSpace(inData);
3501 ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3502 ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3503 osi_FreeLargeSpace(inData);
3506 * We map uid 0 to nobody to match the mapping that the nfs
3507 * server does and to ensure that the suser() calls in the afs
3508 * code fails for remote client roots.
3510 uid = afs_nobody; /* NFS_NOBODY == -2 */
3513 #ifdef AFS_AIX41_ENV
3516 newcred->cr_gid = RMTUSER_REQ;
3517 newcred->cr_groups[0] = g0;
3518 newcred->cr_groups[1] = g1;
3520 newcred->cr_ngrps = 2;
3522 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3523 newcred->cr_ngroups = 2;
3525 for (i=2; i<NGROUPS; i++)
3526 newcred->cr_groups[i] = NOGROUP;
3529 #if !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3530 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
3532 if (!(exporter = exporter_find(exporter_type))) {
3533 /* Exporter wasn't initialized or an invalid exporter type */
3537 if (exporter->exp_states & EXP_PWSYNC) {
3538 if (uid != credp->cr_uid) {
3540 return ENOEXEC; /* XXX Find a better errno XXX */
3543 newcred->cr_uid = uid; /* Only temporary */
3544 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3545 /* The client's pag is the only unique identifier for it */
3546 newcred->cr_uid = pag;
3548 if (!code && *com == PSETPAG) {
3549 /* Special case for 'setpag' */
3550 afs_uint32 pagvalue = genpag();
3552 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3554 * Note that we leave the 'outexporter' struct held so it won't
3557 au->exporter = outexporter;
3558 if (ablob->out_size >= 4) {
3559 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3561 afs_PutUser(au, WRITE_LOCK);
3562 if (code) return code;
3563 return PSETPAG; /* Special return for setpag */
3565 EXP_RELE(outexporter);
3568 #endif /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3571 /* get all interface addresses of this client */
3574 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3577 struct vrequest *areq;
3580 afs_int32 *aoutSize;
3582 struct sprefrequest *spin; /* input */
3583 struct sprefinfo *spout; /* output */
3584 struct spref *srvout; /* one output component */
3588 AFS_STATCNT(PGetCPrefs);
3589 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3590 return EIO; /* Inappropriate ioctl for device */
3592 if ( ainSize < sizeof (struct sprefrequest ))
3595 spin = (struct sprefrequest *) ain;
3596 spout = (struct sprefinfo *) aout;
3598 maxNumber = spin->num_servers; /* max addrs this time */
3599 srvout = spout->servers;
3601 ObtainReadLock(&afs_xinterface);
3603 /* copy out the client interface information from the
3604 ** kernel data structure "interface" to the output buffer
3606 for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3607 && ( j< maxNumber) ; i++, j++, srvout++)
3608 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3610 spout->num_servers = j;
3611 *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3613 if ( i >= afs_cb_interface.numberOfInterfaces )
3614 spout->next_offset = 0; /* start from beginning again */
3616 spout->next_offset = spin->offset + j;
3618 ReleaseReadLock(&afs_xinterface);
3623 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3626 struct vrequest *areq;
3629 afs_int32 *aoutSize;
3631 struct setspref *sin;
3634 AFS_STATCNT(PSetCPrefs);
3635 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3636 return EIO; /* Inappropriate ioctl for device */
3638 sin = (struct setspref *)ain;
3640 if ( ainSize < sizeof(struct setspref) )
3642 #if 0 /* num_servers is unsigned */
3643 if ( sin->num_servers < 0 )
3646 if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3649 ObtainWriteLock(&afs_xinterface, 412);
3650 afs_cb_interface.numberOfInterfaces = sin->num_servers;
3651 for ( i=0; (unsigned short)i < sin->num_servers; i++)
3652 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3654 ReleaseWriteLock(&afs_xinterface);
3658 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3661 struct vrequest *areq;
3664 afs_int32 *aoutSize;
3665 struct AFS_UCRED *acred; {
3666 register afs_int32 code;
3667 register struct vcache *tvc;
3668 register struct dcache *tdc;
3669 struct VenusFid tfid;
3671 struct sysname_info sysState;
3672 afs_size_t offset, len;
3674 AFS_STATCNT(PFlushMount);
3675 if (!avc) return EINVAL;
3676 code = afs_VerifyVCache(avc, areq);
3677 if (code) return code;
3678 if (vType(avc) != VDIR) {
3681 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
3682 if (!tdc) return ENOENT;
3683 Check_AtSys(avc, ain, &sysState, areq);
3684 ObtainReadLock(&tdc->lock);
3686 code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
3687 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
3688 ReleaseReadLock(&tdc->lock);
3689 afs_PutDCache(tdc); /* we're done with the data */
3690 bufp = sysState.name;
3694 tfid.Cell = avc->fid.Cell;
3695 tfid.Fid.Volume = avc->fid.Fid.Volume;
3696 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3697 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3699 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3706 if (vType(tvc) != VLNK) {
3707 afs_PutVCache(tvc, WRITE_LOCK);
3711 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3712 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3714 ObtainWriteLock(&tvc->lock,649);
3715 ObtainWriteLock(&afs_xcbhash, 650);
3716 afs_DequeueCallback(tvc);
3717 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
3718 ReleaseWriteLock(&afs_xcbhash);
3719 /* now find the disk cache entries */
3720 afs_TryToSmush(tvc, acred, 1);
3721 osi_dnlc_purgedp(tvc);
3722 afs_symhint_inval(tvc);
3723 if (tvc->linkData && !(tvc->states & CCore)) {
3724 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3725 tvc->linkData = (char *) 0;
3727 ReleaseWriteLock(&tvc->lock);
3728 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3729 afs_BozonUnlock(&tvc->pvnLock, tvc);
3731 afs_PutVCache(tvc, WRITE_LOCK);
3733 if (sysState.allocked) osi_FreeLargeSpace(bufp);
3737 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3740 struct vrequest *areq;
3743 afs_int32 *aoutSize;
3744 struct AFS_UCRED *acred;
3749 if (!afs_osi_suser(acred)) {
3753 if (ainSize != sizeof(afs_int32)) {
3757 memcpy((char *)&flags, ain, sizeof(afs_int32));
3758 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3762 if (flags & AFSCALL_RXSTATS_ENABLE) {
3763 rx_enableProcessRPCStats();
3765 if (flags & AFSCALL_RXSTATS_DISABLE) {
3766 rx_disableProcessRPCStats();
3768 if (flags & AFSCALL_RXSTATS_CLEAR) {
3769 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3777 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3780 struct vrequest *areq;
3783 afs_int32 *aoutSize;
3784 struct AFS_UCRED *acred;
3789 if (!afs_osi_suser(acred)) {
3793 if (ainSize != sizeof(afs_int32)) {
3797 memcpy((char *)&flags, ain, sizeof(afs_int32));
3798 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3802 if (flags & AFSCALL_RXSTATS_ENABLE) {
3803 rx_enablePeerRPCStats();
3805 if (flags & AFSCALL_RXSTATS_DISABLE) {
3806 rx_disablePeerRPCStats();
3808 if (flags & AFSCALL_RXSTATS_CLEAR) {
3809 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
3816 static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
3819 struct vrequest *areq;
3822 afs_int32 *aoutSize; /* set this */
3824 register afs_int32 code, code1;
3827 struct rx_call *tcall;
3828 struct AFSVolSync tsync;
3829 struct AFSFetchStatus OutStatus;
3830 struct AFSCallBack CallBack;
3831 struct VenusFid tfid;
3836 AFS_STATCNT(PSetAcl);
3840 if (ain && (ainSize == 3 * sizeof(afs_int32)))
3841 Fid = (struct AFSFid *) ain;
3843 Fid = &avc->fid.Fid;
3844 tfid.Cell = avc->fid.Cell;
3845 tfid.Fid.Volume = Fid->Volume;
3846 tfid.Fid.Vnode = Fid->Vnode;
3847 tfid.Fid.Unique = Fid->Unique;
3849 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3852 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3853 ICL_TYPE_POINTER, tvc,
3854 ICL_TYPE_FID, &tfid,
3855 ICL_TYPE_FID, &avc->fid);
3858 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
3859 ICL_TYPE_POINTER, tvc,
3860 ICL_TYPE_FID, &tfid,
3861 ICL_TYPE_FID, &tvc->fid);
3864 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3867 #ifdef RX_ENABLE_LOCKS
3869 #endif /* RX_ENABLE_LOCKS */
3870 tcall = rx_NewCall(tc->id);
3871 code = StartRXAFS_FetchData(tcall,
3872 (struct AFSFid *) &tvc->fid.Fid, 0, 0);
3874 bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
3875 code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
3877 code1 = rx_EndCall(tcall, code);
3878 #ifdef RX_ENABLE_LOCKS
3880 #endif /* RX_ENABLE_LOCKS */
3884 (afs_Analyze(tc, code, &tvc->fid, areq,
3885 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3887 /* This call is done only to have the callback things handled correctly */
3888 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
3889 afs_PutVCache(tvc, WRITE_LOCK);
3892 *aoutSize = sizeof(afs_int32);
3897 static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
3900 struct vrequest *areq;
3903 afs_int32 *aoutSize; /* set this */
3905 register afs_int32 code;
3908 struct ResidencyCmdInputs *Inputs;
3909 struct ResidencyCmdOutputs *Outputs;
3910 struct VenusFid tfid;
3913 Inputs = (struct ResidencyCmdInputs *) ain;
3914 Outputs = (struct ResidencyCmdOutputs *) aout;
3915 if (!avc) return EINVAL;
3916 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
3920 Fid = &avc->fid.Fid;
3922 tfid.Cell = avc->fid.Cell;
3923 tfid.Fid.Volume = Fid->Volume;
3924 tfid.Fid.Vnode = Fid->Vnode;
3925 tfid.Fid.Unique = Fid->Unique;
3927 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
3929 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
3930 ICL_TYPE_POINTER, tvc,
3931 ICL_TYPE_INT32, Inputs->command,
3932 ICL_TYPE_FID, &tfid);
3936 if (Inputs->command) {
3938 tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
3940 #ifdef RX_ENABLE_LOCKS
3942 #endif /* RX_ENABLE_LOCKS */
3943 code = RXAFS_ResidencyCmd(tc->id, Fid,
3945 (struct ResidencyCmdOutputs *) aout);
3946 #ifdef RX_ENABLE_LOCKS
3948 #endif /* RX_ENABLE_LOCKS */
3952 (afs_Analyze(tc, code, &tvc->fid, areq,
3953 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
3955 /* This call is done to have the callback things handled correctly */
3956 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3957 } else { /* just a status request, return also link data */
3959 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
3960 Outputs->chars[0] = 0;
3961 if (vType(tvc) == VLNK) {
3962 ObtainWriteLock(&tvc->lock,555);
3963 if (afs_HandleLink(tvc, areq) == 0)
3964 strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
3965 ReleaseWriteLock(&tvc->lock);
3969 afs_PutVCache(tvc, WRITE_LOCK);
3972 *aoutSize = sizeof(struct ResidencyCmdOutputs);