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 "../afs/param.h" /* Should be always first */
11 #include "../afs/sysincludes.h" /* Standard vendor system headers */
12 #include "../afs/afsincludes.h" /* Afs-based standard headers */
13 #include "../afs/afs_stats.h" /* afs statistics */
14 #include "../afs/vice.h"
15 #include "../rx/rx_globals.h"
17 extern void afs_ComputePAGStats();
18 extern struct vcache *afs_LookupVCache();
19 struct VenusFid afs_rootFid;
20 afs_int32 afs_waitForever=0;
21 short afs_waitForeverCount = 0;
22 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
23 extern afs_int32 PROBE_INTERVAL;
25 extern int cacheDiskType;
26 extern afs_int32 afs_cacheBlocks;
27 extern struct afs_q CellLRU;
28 extern char *afs_indexFlags; /* only one: is there data there? */
29 extern afs_int32 afs_blocksUsed;
30 extern struct unixuser *afs_users[NUSERS];
31 extern struct server *afs_servers[NSERVERS];
32 extern struct interfaceAddr afs_cb_interface; /* client interface addresses */
33 extern afs_rwlock_t afs_xserver;
34 extern afs_rwlock_t afs_xinterface;
35 extern afs_rwlock_t afs_xcell;
36 extern afs_rwlock_t afs_xuser;
37 #ifndef AFS_FINEG_SUNLOCK
38 extern afs_rwlock_t afs_xconn;
40 extern afs_rwlock_t afs_xvolume;
41 extern afs_lock_t afs_xdcache; /* lock: alloc new disk cache entries */
42 extern afs_rwlock_t afs_xvcache;
43 extern afs_rwlock_t afs_xcbhash;
44 extern afs_int32 afs_mariner, afs_marinerHost;
45 extern struct srvAddr *afs_srvAddrs[NSERVERS];
46 extern int afs_resourceinit_flag;
48 static int PBogus(), PSetAcl(), PGetAcl(), PSetTokens(), PGetVolumeStatus();
49 static int PSetVolumeStatus(), PFlush(), PNewStatMount(), PGetTokens(), PUnlog();
50 static int PCheckServers(), PCheckVolNames(), PCheckAuth(), PFindVolume();
51 static int PViceAccess(), PSetCacheSize(), Prefetch();
52 static int PRemoveCallBack(), PNewCell(), PListCells(), PRemoveMount();
53 static int PMariner(), PGetUserCell(), PGetWSCell(), PGetFileCell();
54 static int PVenusLogging(), PNoop(), PSetCellStatus(), PGetCellStatus();
55 static int PFlushVolumeData(), PGetCacheSize();
56 static int PSetSysName(),PGetFID();
57 static int PGetVnodeXStatus();
58 static int PSetSPrefs(), PGetSPrefs(), PGag(), PTwiddleRx();
59 static int PSetSPrefs33(), PStoreBehind(), PGCPAGs();
60 static int PGetCPrefs(), PSetCPrefs(); /* client network addresses */
61 static int PGetInitParams(), PFlushMount(), PRxStatProc(), PRxStatPeer();
64 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp);
66 extern struct cm_initparams cm_initParams;
68 static int (*(pioctlSw[]))() = {
73 PGetVolumeStatus, /* 4 */
74 PSetVolumeStatus, /* 5 */
79 PCheckServers, /* 10 */
80 PCheckVolNames, /* 11 */
82 PBogus, /* 13 -- used to be quick check time */
84 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
85 PBogus, /* 16 -- used to be testing code */
86 PNoop, /* 17 -- used to be enable group */
87 PNoop, /* 18 -- used to be disable group */
88 PBogus, /* 19 -- used to be list group */
90 PUnlog, /* 21 -- unlog *is* unpag in this system */
91 PGetFID, /* 22 -- get file ID */
92 PBogus, /* 23 -- used to be waitforever */
93 PSetCacheSize, /* 24 */
94 PRemoveCallBack, /* 25 -- flush only the callback */
97 PRemoveMount, /* 28 -- delete mount point */
98 PNewStatMount, /* 29 -- new style mount point stat */
99 PGetFileCell, /* 30 -- get cell name for input file */
100 PGetWSCell, /* 31 -- get cell name for workstation */
101 PMariner, /* 32 - set/get mariner host */
102 PGetUserCell, /* 33 -- get cell name for user */
103 PVenusLogging, /* 34 -- Enable/Disable logging */
104 PGetCellStatus, /* 35 */
105 PSetCellStatus, /* 36 */
106 PFlushVolumeData, /* 37 -- flush all data from a volume */
107 PSetSysName, /* 38 - Set system name */
108 PExportAfs, /* 39 - Export Afs to remote nfs clients */
109 PGetCacheSize, /* 40 - get cache size and usage */
110 PGetVnodeXStatus, /* 41 - get vcache's special status */
111 PSetSPrefs33, /* 42 - Set CM Server preferences... */
112 PGetSPrefs, /* 43 - Get CM Server preferences... */
113 PGag, /* 44 - turn off/on all CM messages */
114 PTwiddleRx, /* 45 - adjust some RX params */
115 PSetSPrefs, /* 46 - Set CM Server preferences... */
116 PStoreBehind, /* 47 - set degree of store behind to be done */
117 PGCPAGs, /* 48 - disable automatic pag gc-ing */
118 PGetInitParams, /* 49 - get initial cm params */
119 PGetCPrefs, /* 50 - get client interface addresses */
120 PSetCPrefs, /* 51 - set client interface addresses */
121 PFlushMount, /* 52 - flush mount symlink data */
122 PRxStatProc, /* 53 - control process RX statistics */
123 PRxStatPeer, /* 54 - control peer RX statistics */
126 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
127 int afs_nobody = NFS_NOBODY;
130 afs_ioctl32_to_afs_ioctl(const struct afs_ioctl32 *src, struct afs_ioctl *dst)
132 dst->in = (char *)(unsigned long)src->in;
133 dst->out = (char *)(unsigned long)src->out;
134 dst->in_size = src->in_size;
135 dst->out_size = src->out_size;
139 * If you need to change copyin_afs_ioctl(), you may also need to change
144 copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
148 #if defined(AFS_HPUX_64BIT_ENV)
149 struct afs_ioctl32 dst32;
151 if (is_32bit(u.u_procp)) /* is_32bit() in proc_iface.h */
153 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
155 afs_ioctl32_to_afs_ioctl(&dst32, dst);
158 #endif /* defined(AFS_HPUX_64BIT_ENV) */
160 #if defined(AFS_SUN57_64BIT_ENV)
161 struct afs_ioctl32 dst32;
163 if (get_udatamodel() == DATAMODEL_ILP32) {
164 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
166 afs_ioctl32_to_afs_ioctl(&dst32, dst);
169 #endif /* defined(AFS_SUN57_64BIT_ENV) */
171 #if defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64)
172 struct afs_ioctl32 dst32;
174 if (!ABI_IS_64BIT(get_current_abi()))
176 AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
178 afs_ioctl32_to_afs_ioctl(&dst32, dst);
181 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
183 AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
187 HandleIoctl(avc, acom, adata)
188 register struct vcache *avc;
189 register afs_int32 acom;
190 struct afs_ioctl *adata; {
191 register afs_int32 code;
194 AFS_STATCNT(HandleIoctl);
196 switch(acom & 0xff) {
198 avc->states |= CSafeStore;
202 /* case 2 used to be abort store, but this is no longer provided,
203 since it is impossible to implement under normal Unix.
207 /* return the name of the cell this file is open on */
208 register struct cell *tcell;
209 register afs_int32 i;
211 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
213 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
215 if (i > adata->out_size) {
216 /* 0 means we're not interested in the output */
217 if (adata->out_size != 0) code = EFAULT;
221 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
223 afs_PutCell(tcell, READ_LOCK);
229 case 49: /* VIOC_GETINITPARAMS */
230 if (adata->out_size < sizeof(struct cm_initparams)) {
234 AFS_COPYOUT(&cm_initParams, adata->out,
235 sizeof(struct cm_initparams), code);
244 return code; /* so far, none implemented */
249 /* For aix we don't temporarily bypass ioctl(2) but rather do our
250 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
251 * is now called from afs_gn_ioctl.
253 afs_ioctl(tvc, cmd, arg)
258 struct afs_ioctl data;
261 AFS_STATCNT(afs_ioctl);
262 if (((cmd >> 8) & 0xff) == 'V') {
263 /* This is a VICEIOCTL call */
264 AFS_COPYIN(arg, (caddr_t) &data, sizeof(data), error);
267 error = HandleIoctl(tvc, cmd, &data);
270 /* No-op call; just return. */
274 #endif /* AFS_AIX_ENV */
276 #if defined(AFS_SGI_ENV)
277 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void * arg, int flag, cred_t *cr, rval_t *rvalp
283 struct afs_ioctl data;
289 AFS_STATCNT(afs_ioctl);
290 if (((cmd >> 8) & 0xff) == 'V') {
291 /* This is a VICEIOCTL call */
292 error = copyin_afs_ioctl(arg, &data);
295 locked = ISAFS_GLOCK();
298 error = HandleIoctl(tvc, cmd, &data);
303 /* No-op call; just return. */
307 #endif /* AFS_SGI_ENV */
310 /* unlike most calls here, this one uses u.u_error to return error conditions,
311 since this is really an intercepted chapter 2 call, rather than a vnode
314 /* AFS_HPUX102 and up uses VNODE ioctl instead */
315 #ifndef AFS_HPUX102_ENV
316 #if !defined(AFS_SGI_ENV)
318 kioctl(fdes, com, arg, ext)
325 } u_uap, *uap = &u_uap;
329 struct afs_ioctl_sys {
335 afs_xioctl (uap, rvp)
336 struct afs_ioctl_sys *uap;
341 afs_xioctl (p, args, retval)
350 } *uap = (struct a *)args;
351 #else /* AFS_OSF_ENV */
352 #ifdef AFS_LINUX22_ENV
353 struct afs_ioctl_sys {
357 asmlinkage int afs_xioctl(struct inode *ip, struct file *fp,
358 unsigned int com, unsigned long arg)
360 struct afs_ioctl_sys ua, *uap = &ua;
368 } *uap = (struct a *)u.u_ap;
369 #endif /* AFS_LINUX22_ENV */
370 #endif /* AFS_OSF_ENV */
371 #endif /* AFS_SUN5_ENV */
373 #ifndef AFS_LINUX22_ENV
374 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV)
377 register struct file *fd;
380 register struct vcache *tvc;
381 register int ioctlDone = 0, code = 0;
383 AFS_STATCNT(afs_xioctl);
384 #ifdef AFS_LINUX22_ENV
392 if (setuerror(getf(uap->fd, &fd))) {
398 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
400 #else /* AFS_OSF_ENV */
402 #if defined(AFS_SUN57_ENV)
404 if (!fd) return(EBADF);
405 #elif defined(AFS_SUN54_ENV)
407 if (!fd) return(EBADF);
409 if (code = getf(uap->fd, &fd)) {
421 /* first determine whether this is any sort of vnode */
422 #ifdef AFS_LINUX22_ENV
423 tvc = (struct vcache *)ip;
427 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
429 if (fd->f_type == DTYPE_VNODE) {
431 /* good, this is a vnode; next see if it is an AFS vnode */
432 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
433 tvc = (struct vcache *) fd->f_vnode; /* valid, given a vnode */
435 tvc = (struct vcache *) fd->f_data; /* valid, given a vnode */
437 #endif /* AFS_LINUX22_ENV */
438 if (tvc && IsAfsVnode((struct vnode *)tvc)) {
440 tvc = (struct vcache *) afs_gntovn((struct gnode *) tvc);
441 if (!tvc) { /* shouldn't happen with held gnodes */
446 /* This is an AFS vnode */
447 if (((uap->com >> 8) & 0xff) == 'V') {
448 register struct afs_ioctl *datap;
450 datap = (struct afs_ioctl *) osi_AllocSmallSpace(AFS_SMALLOCSIZ);
451 AFS_COPYIN((char *)uap->arg, (caddr_t) datap, sizeof (struct afs_ioctl), code);
453 osi_FreeSmallSpace(datap);
455 #if defined(AFS_SUN5_ENV)
470 #else /* AFS_OSF_ENV */
474 #ifdef AFS_LINUX22_ENV
483 code = HandleIoctl(tvc, uap->com, datap);
484 osi_FreeSmallSpace(datap);
498 #if defined(AFS_LINUX22_ENV)
508 code = okioctl(fdes, com, arg, ext);
512 okioctl(fdes, com, arg, ext);
514 #if defined(AFS_SUN5_ENV)
515 #if defined(AFS_SUN57_ENV)
517 #elif defined(AFS_SUN54_ENV)
522 code = ioctl(uap, rvp);
525 code = ioctl(p, args, retval);
532 #else /* AFS_OSF_ENV */
533 #ifndef AFS_LINUX22_ENV
550 #ifdef AFS_LINUX22_ENV
553 #if !defined(AFS_OSF_ENV)
556 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
557 return (getuerror() ? -1 : u.u_ioctlrv);
559 return getuerror() ? -1 : 0;
562 #endif /* AFS_LINUX22_ENV */
563 #endif /* AFS_SUN5_ENV */
568 #endif /* AFS_SGI_ENV */
569 #endif /* AFS_HPUX102_ENV */
571 #if defined(AFS_SGI_ENV)
572 /* "pioctl" system call entry point; just pass argument to the parameterized
581 afs_pioctl(struct pioctlargs *uap, rval_t *rvp)
585 AFS_STATCNT(afs_pioctl);
587 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
595 #endif /* AFS_SGI_ENV */
598 afs_pioctl(p, args, retval)
608 } *uap = (struct a *) args;
610 AFS_STATCNT(afs_pioctl);
611 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
614 extern struct mount *afs_globalVFS;
615 #else /* AFS_OSF_ENV */
616 extern struct vfs *afs_globalVFS;
619 /* macro to avoid adding any more #ifdef's to pioctl code. */
620 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
621 #define PIOCTL_FREE_CRED() crfree(credp)
623 #define PIOCTL_FREE_CRED()
627 afs_syscall_pioctl(path, com, cmarg, follow, rvp, credp)
629 struct AFS_UCRED *credp;
631 afs_syscall_pioctl(path, com, cmarg, follow)
638 struct afs_ioctl data;
639 struct AFS_UCRED *tmpcred, *foreigncreds = 0;
640 register afs_int32 code = 0;
646 struct ucred *credp = crref(); /* don't free until done! */
648 #ifdef AFS_LINUX22_ENV
649 cred_t *credp = crref(); /* don't free until done! */
652 AFS_STATCNT(afs_syscall_pioctl);
653 if (follow) follow = 1; /* compat. with old venus */
655 if (! _VALIDVICEIOCTL(com)) {
659 #else /* AFS_OSF_ENV */
660 #if defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
669 code = copyin_afs_ioctl(cmarg, &data);
672 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
679 if ((com & 0xff) == PSetClientContext) {
680 #ifdef AFS_LINUX22_ENV
681 return EINVAL; /* Not handling these yet. */
683 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
684 code = HandleClientContext(&data, &com, &foreigncreds, credp);
686 #if defined(AFS_HPUX101_ENV)
687 code=HandleClientContext(&data, &com, &foreigncreds, p_cred(u.u_procp));
690 code = HandleClientContext(&data, &com, &foreigncreds, OSI_GET_CURRENT_CRED());
692 code = HandleClientContext(&data, &com, &foreigncreds, u.u_cred);
693 #endif /* AFS_SGI_ENV */
698 crfree(foreigncreds);
701 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
704 return (setuerror(code), code);
708 #ifndef AFS_LINUX22_ENV
711 * We could have done without temporary setting the u.u_cred below
712 * (foreigncreds could be passed as param the pioctl modules)
713 * but calls such as afs_osi_suser() doesn't allow that since it
714 * references u.u_cred directly. We could, of course, do something
715 * like afs_osi_suser(cred) which, I think, is better since it
716 * generalizes and supports multi cred environments...
720 credp = foreigncreds;
723 tmpcred = crref(); /* XXX */
726 #if defined(AFS_HPUX101_ENV)
727 tmpcred = p_cred(u.u_procp);
728 set_p_cred(u.u_procp, foreigncreds);
731 tmpcred = OSI_GET_CURRENT_CRED();
732 OSI_SET_CURRENT_CRED(foreigncreds);
735 u.u_cred = foreigncreds;
736 #endif /* AFS_SGI64_ENV */
737 #endif /* AFS_HPUX101_ENV */
742 if ((com & 0xff) == 15) {
743 /* special case prefetch so entire pathname eval occurs in helper process.
744 otherwise, the pioctl call is essentially useless */
745 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
746 code = Prefetch(path, &data, follow,
747 foreigncreds ? foreigncreds : credp);
749 #if defined(AFS_HPUX101_ENV)
750 code = Prefetch(path, &data, follow, p_cred(u.u_procp));
753 code = Prefetch(path, &data, follow, OSI_GET_CURRENT_CRED());
755 code = Prefetch(path, &data, follow, u.u_cred);
756 #endif /* AFS_SGI64_ENV */
757 #endif /* AFS_HPUX101_ENV */
759 #ifndef AFS_LINUX22_ENV
762 crset(tmpcred); /* restore original credentials */
764 #if defined(AFS_HPUX101_ENV)
765 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
769 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
771 u.u_cred = tmpcred; /* restore original credentials */
774 #endif /* AFS_HPUX101_ENV */
775 crfree(foreigncreds);
778 #endif /* AFS_LINUX22_ENV */
780 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
783 return (setuerror(code), code);
789 code = lookupname(path, USR, follow, NULL, &vp,
790 foreigncreds ? foreigncreds : credp);
792 #ifdef AFS_LINUX22_ENV
793 code = gop_lookupname(path, AFS_UIOUSER, follow, (struct vnode **) 0, &dp);
795 vp = (struct vcache *)dp->d_inode;
797 code = gop_lookupname(path, AFS_UIOUSER, follow, (struct vnode **) 0, &vp);
798 #endif /* AFS_LINUX22_ENV */
799 #endif /* AFS_AIX41_ENV */
802 #ifndef AFS_LINUX22_ENV
805 crset(tmpcred); /* restore original credentials */
807 #if defined(AFS_HPUX101_ENV)
808 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
810 #if !defined(AFS_SUN5_ENV)
812 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
814 u.u_cred = tmpcred; /* restore original credentials */
815 #endif /* AFS_SGI64_ENV */
817 #endif /* AFS_HPUX101_ENV */
818 crfree(foreigncreds);
821 #endif /* AFS_LINUX22_ENV */
823 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
826 return(setuerror(code), code);
830 else vp = (struct vnode *) 0;
832 /* now make the call if we were passed no file, or were passed an AFS file */
833 if (!vp || IsAfsVnode(vp)) {
835 /* Ultrix 4.0: can't get vcache entry unless we've got an AFS gnode.
836 * So, we must test in this part of the code. Also, must arrange to
837 * GRELE the original gnode pointer when we're done, since in Ultrix 4.0,
838 * we hold gnodes, whose references hold our vcache entries.
841 gp = vp; /* remember for "put" */
842 vp = (struct vnode *) afs_gntovn(vp); /* get vcache from gp */
844 else gp = (struct vnode *) 0;
847 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
851 struct ucred *cred1, *cred2;
854 cred1 = cred2 = foreigncreds;
856 cred1 = cred2 = credp;
858 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
859 if (cred1 != cred2) {
860 /* something changed the creds */
865 #if defined(AFS_HPUX101_ENV)
867 struct ucred *cred = p_cred(u.u_procp);
868 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
874 credp = OSI_GET_CURRENT_CRED();
875 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
878 #ifdef AFS_LINUX22_ENV
879 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
881 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
883 #endif /* AFS_SGI_ENV */
884 #endif /* AFS_HPUX101_ENV */
885 #endif /* AFS_AIX41_ENV */
886 #endif /* AFS_SUN5_ENV */
888 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
889 code = EINVAL; /* not in /afs */
896 vp = (struct vnode *) 0;
901 #ifndef AFS_LINUX22_ENV
906 #if defined(AFS_HPUX101_ENV)
907 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
911 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
913 u.u_cred = tmpcred; /* restore original credentials */
914 #endif /* ASF_SGI64_ENV */
916 #endif /* AFS_HPUX101_ENV */
917 crfree(foreigncreds);
920 #endif /* AFS_LINUX22_ENV */
922 #ifdef AFS_LINUX22_ENV
925 AFS_RELE(vp); /* put vnode back */
929 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
934 return (getuerror());
939 afs_HandlePioctl(avc, acom, ablob, afollow, acred)
940 register struct vcache *avc;
942 struct AFS_UCRED **acred;
943 register struct afs_ioctl *ablob;
946 struct vrequest treq;
947 register afs_int32 code;
948 register afs_int32 function;
949 afs_int32 inSize, outSize;
950 char *inData, *outData;
952 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
953 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
954 AFS_STATCNT(HandlePioctl);
955 if (code = afs_InitReq(&treq, *acred)) return code;
956 function = acom & 0xff;
957 if (function >= (sizeof(pioctlSw) / sizeof(char *))) {
958 return EINVAL; /* out of range */
960 inSize = ablob->in_size;
961 if (inSize >= PIGGYSIZE) return E2BIG;
962 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
964 AFS_COPYIN(ablob->in, inData, inSize, code);
968 osi_FreeLargeSpace(inData);
971 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
973 if (function == 3) /* PSetTokens */
974 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, acred);
976 code = (*pioctlSw[function])(avc, function, &treq, inData, outData, inSize, &outSize, *acred);
977 osi_FreeLargeSpace(inData);
978 if (code == 0 && ablob->out_size > 0) {
979 if (outSize > ablob->out_size) outSize = ablob->out_size;
980 if (outSize >= PIGGYSIZE) code = E2BIG;
982 AFS_COPYOUT(outData, ablob->out, outSize, code);
984 osi_FreeLargeSpace(outData);
985 return afs_CheckCode(code, &treq, 41);
988 static PGetFID(avc, afun, areq, ain, aout, ainSize, aoutSize)
991 struct vrequest *areq;
994 afs_int32 *aoutSize; /* set this */ {
995 register afs_int32 code;
997 AFS_STATCNT(PGetFID);
998 if (!avc) return EINVAL;
999 bcopy((char *)&avc->fid, aout, sizeof(struct VenusFid));
1000 *aoutSize = sizeof(struct VenusFid);
1004 static PSetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1007 struct vrequest *areq;
1010 afs_int32 *aoutSize; /* set this */ {
1011 register afs_int32 code;
1013 struct AFSOpaque acl;
1014 struct AFSVolSync tsync;
1015 struct AFSFetchStatus OutStatus;
1018 AFS_STATCNT(PSetAcl);
1021 if ((acl.AFSOpaque_len = strlen(ain)+1) > 1000)
1024 acl.AFSOpaque_val = ain;
1026 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1028 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1029 #ifdef RX_ENABLE_LOCKS
1031 #endif /* RX_ENABLE_LOCKS */
1032 code = RXAFS_StoreACL(tconn->id, (struct AFSFid *) &avc->fid.Fid,
1033 &acl, &OutStatus, &tsync);
1034 #ifdef RX_ENABLE_LOCKS
1036 #endif /* RX_ENABLE_LOCKS */
1041 (afs_Analyze(tconn, code, &avc->fid, areq,
1042 AFS_STATS_FS_RPCIDX_STOREACL, SHARED_LOCK, (struct cell *)0));
1044 /* now we've forgotten all of the access info */
1045 ObtainWriteLock(&afs_xcbhash, 455);
1047 afs_DequeueCallback(avc);
1048 avc->states &= ~(CStatd | CUnique);
1049 ReleaseWriteLock(&afs_xcbhash);
1050 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1051 osi_dnlc_purgedp(avc);
1055 int afs_defaultAsynchrony = 0;
1057 static PStoreBehind(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1060 struct vrequest *areq;
1063 afs_int32 *aoutSize; /* set this */
1064 struct AFS_UCRED *acred;
1067 struct sbstruct *sbr;
1069 sbr = (struct sbstruct *)ain;
1070 if (sbr->sb_default != -1) {
1071 if (afs_osi_suser(acred))
1072 afs_defaultAsynchrony = sbr->sb_default;
1076 if (avc && (sbr->sb_thisfile != -1))
1077 if (afs_AccessOK(avc, PRSFS_WRITE | PRSFS_ADMINISTER,
1078 areq, DONT_CHECK_MODE_BITS))
1079 avc->asynchrony = sbr->sb_thisfile;
1082 *aoutSize = sizeof(struct sbstruct);
1083 sbr = (struct sbstruct *)aout;
1084 sbr->sb_default = afs_defaultAsynchrony;
1086 sbr->sb_thisfile = avc->asynchrony;
1092 static PGCPAGs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1095 struct vrequest *areq;
1098 afs_int32 *aoutSize; /* set this */
1099 struct AFS_UCRED *acred;
1101 if (!afs_osi_suser(acred)) {
1104 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1108 static PGetAcl(avc, afun, areq, ain, aout, ainSize, aoutSize)
1111 struct vrequest *areq;
1114 afs_int32 *aoutSize; /* set this */ {
1115 struct AFSOpaque acl;
1116 struct AFSVolSync tsync;
1117 struct AFSFetchStatus OutStatus;
1123 AFS_STATCNT(PGetAcl);
1124 if (!avc) return EINVAL;
1125 Fid.Volume = avc->fid.Fid.Volume;
1126 Fid.Vnode = avc->fid.Fid.Vnode;
1127 Fid.Unique = avc->fid.Fid.Unique;
1128 if (avc->states & CForeign) {
1130 * For a dfs xlator acl we have a special hack so that the
1131 * xlator will distinguish which type of acl will return. So
1132 * we currently use the top 2-bytes (vals 0-4) to tell which
1133 * type of acl to bring back. Horrible hack but this will
1134 * cause the least number of changes to code size and interfaces.
1136 if (Fid.Vnode & 0xc0000000)
1138 Fid.Vnode |= (ainSize << 30);
1140 acl.AFSOpaque_val = aout;
1142 tconn = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1145 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1146 #ifdef RX_ENABLE_LOCKS
1148 #endif /* RX_ENABLE_LOCKS */
1149 code = RXAFS_FetchACL(tconn->id, &Fid,
1150 &acl, &OutStatus, &tsync);
1151 #ifdef RX_ENABLE_LOCKS
1153 #endif /* RX_ENABLE_LOCKS */
1158 (afs_Analyze(tconn, code, &avc->fid, areq,
1159 AFS_STATS_FS_RPCIDX_FETCHACL,
1160 SHARED_LOCK, (struct cell *)0));
1163 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1174 AFS_STATCNT(PBogus);
1178 static PGetFileCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1181 struct vrequest *areq;
1185 afs_int32 *aoutSize; /* set this */ {
1186 register struct cell *tcell;
1188 AFS_STATCNT(PGetFileCell);
1189 if (!avc) return EINVAL;
1190 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
1191 if (!tcell) return ESRCH;
1192 strcpy(aout, tcell->cellName);
1193 afs_PutCell(tcell, READ_LOCK);
1194 *aoutSize = strlen(aout) + 1;
1198 static PGetWSCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1201 struct vrequest *areq;
1205 afs_int32 *aoutSize; /* set this */ {
1206 register struct cell *tcell=0, *cellOne=0;
1207 register struct afs_q *cq, *tq;
1209 AFS_STATCNT(PGetWSCell);
1210 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1211 return EIO; /* Inappropriate ioctl for device */
1213 ObtainReadLock(&afs_xcell);
1214 cellOne = (struct cell *) 0;
1216 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
1217 tcell = QTOC(cq); tq = QNext(cq);
1218 if (tcell->states & CPrimary) break;
1219 if (tcell->cell == 1) cellOne = tcell;
1222 ReleaseReadLock(&afs_xcell);
1223 if (!tcell) { /* no primary cell, use cell #1 */
1224 if (!cellOne) return ESRCH;
1227 strcpy(aout, tcell->cellName);
1228 *aoutSize = strlen(aout) + 1;
1232 static PGetUserCell(avc, afun, areq, ain, aout, ainSize, aoutSize)
1235 struct vrequest *areq;
1239 afs_int32 *aoutSize; /* set this */ {
1240 register afs_int32 i;
1241 register struct unixuser *tu;
1242 register struct cell *tcell;
1244 AFS_STATCNT(PGetUserCell);
1245 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1246 return EIO; /* Inappropriate ioctl for device */
1248 /* return the cell name of the primary cell for this user */
1249 i = UHash(areq->uid);
1250 ObtainWriteLock(&afs_xuser,224);
1251 for(tu = afs_users[i]; tu; tu = tu->next) {
1252 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1254 ReleaseWriteLock(&afs_xuser);
1259 tcell = afs_GetCell(tu->cell, READ_LOCK);
1260 afs_PutUser(tu, WRITE_LOCK);
1261 if (!tcell) return ESRCH;
1263 strcpy(aout, tcell->cellName);
1264 afs_PutCell(tcell, READ_LOCK);
1265 *aoutSize = strlen(aout)+1; /* 1 for the null */
1269 ReleaseWriteLock(&afs_xuser);
1276 static PSetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1279 struct vrequest *areq;
1283 afs_int32 *aoutSize; /* set this */
1284 struct AFS_UCRED **acred;
1287 register struct unixuser *tu;
1288 struct ClearToken clear;
1289 register struct cell *tcell;
1292 struct vrequest treq;
1293 afs_int32 flag, set_parent_pag = 0;
1295 AFS_STATCNT(PSetTokens);
1296 if (!afs_resourceinit_flag) {
1299 bcopy(ain, (char *)&i, sizeof(afs_int32));
1300 ain += sizeof(afs_int32);
1301 stp = ain; /* remember where the ticket is */
1302 if (i < 0 || i > 2000) return EINVAL; /* malloc may fail */
1304 ain += i; /* skip over ticket */
1305 bcopy(ain, (char *)&i, sizeof(afs_int32));
1306 ain += sizeof(afs_int32);
1307 if (i != sizeof(struct ClearToken)) {
1310 bcopy(ain, (char *)&clear, sizeof(struct ClearToken));
1311 if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */
1312 ain += sizeof(struct ClearToken);
1313 if (ainSize != 2*sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1314 /* still stuff left? we've got primary flag and cell name. Set these */
1315 bcopy(ain, (char *)&flag, sizeof(afs_int32)); /* primary id flag */
1316 ain += sizeof(afs_int32); /* skip id field */
1317 /* rest is cell name, look it up */
1318 if (flag & 0x8000) { /* XXX Use Constant XXX */
1322 tcell = afs_GetCellByName(ain, READ_LOCK);
1331 /* default to cell 1, primary id */
1332 flag = 1; /* primary id */
1333 i = 1; /* cell number */
1334 tcell = afs_GetCell(1, READ_LOCK);
1335 if (!tcell) goto nocell;
1337 afs_PutCell(tcell, READ_LOCK);
1338 if (set_parent_pag) {
1341 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1343 if (!setpag(acred, -1, &pag, 1)) {
1345 afs_InitReq(&treq, *acred);
1349 /* now we just set the tokens */
1350 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1351 tu->vid = clear.ViceId;
1352 if (tu->stp != (char *) 0) {
1353 afs_osi_Free(tu->stp, tu->stLen);
1355 tu->stp = (char *) afs_osi_Alloc(stLen);
1357 bcopy(stp, tu->stp, stLen);
1360 afs_stats_cmfullperf.authent.TicketUpdates++;
1361 afs_ComputePAGStats();
1362 #endif /* AFS_NOSTATS */
1363 tu->states |= UHasTokens;
1364 tu->states &= ~UTokensBad;
1365 afs_SetPrimary(tu, flag);
1366 tu->tokenTime =osi_Time();
1367 afs_ResetUserConns(tu);
1368 afs_PutUser(tu, WRITE_LOCK);
1383 static PGetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1386 struct vrequest *areq;
1389 afs_int32 *aoutSize; /* set this */ {
1391 char offLineMsg[256];
1393 register struct conn *tc;
1394 register afs_int32 code;
1395 struct VolumeStatus volstat;
1397 char *Name, *OfflineMsg, *MOTD;
1400 AFS_STATCNT(PGetVolumeStatus);
1401 if (!avc) return EINVAL;
1403 OfflineMsg = offLineMsg;
1406 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1408 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1409 #ifdef RX_ENABLE_LOCKS
1411 #endif /* RX_ENABLE_LOCKS */
1412 code = RXAFS_GetVolumeStatus(tc->id, avc->fid.Fid.Volume, &volstat,
1413 &Name, &OfflineMsg, &MOTD);
1414 #ifdef RX_ENABLE_LOCKS
1416 #endif /* RX_ENABLE_LOCKS */
1421 (afs_Analyze(tc, code, &avc->fid, areq,
1422 AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1423 SHARED_LOCK, (struct cell *)0));
1425 if (code) return code;
1426 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1428 bcopy((char *)&volstat, cp, sizeof(VolumeStatus));
1429 cp += sizeof(VolumeStatus);
1430 strcpy(cp, volName);
1431 cp += strlen(volName)+1;
1432 strcpy(cp, offLineMsg);
1433 cp += strlen(offLineMsg)+1;
1435 cp += strlen(motd)+1;
1436 *aoutSize = (cp - aout);
1440 static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
1443 struct vrequest *areq;
1446 afs_int32 *aoutSize; /* set this */ {
1448 char offLineMsg[256];
1450 register struct conn *tc;
1451 register afs_int32 code;
1452 struct AFSFetchVolumeStatus volstat;
1453 struct AFSStoreVolumeStatus storeStat;
1454 register struct volume *tvp;
1458 AFS_STATCNT(PSetVolumeStatus);
1459 if (!avc) return EINVAL;
1461 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1463 if (tvp->states & (VRO | VBackup)) {
1464 afs_PutVolume(tvp, READ_LOCK);
1467 afs_PutVolume(tvp, READ_LOCK);
1470 /* Copy the junk out, using cp as a roving pointer. */
1472 bcopy(cp, (char *)&volstat, sizeof(AFSFetchVolumeStatus));
1473 cp += sizeof(AFSFetchVolumeStatus);
1474 strcpy(volName, cp);
1475 cp += strlen(volName)+1;
1476 strcpy(offLineMsg, cp);
1477 cp += strlen(offLineMsg)+1;
1480 if (volstat.MinQuota != -1) {
1481 storeStat.MinQuota = volstat.MinQuota;
1482 storeStat.Mask |= AFS_SETMINQUOTA;
1484 if (volstat.MaxQuota != -1) {
1485 storeStat.MaxQuota = volstat.MaxQuota;
1486 storeStat.Mask |= AFS_SETMAXQUOTA;
1489 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
1491 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1492 #ifdef RX_ENABLE_LOCKS
1494 #endif /* RX_ENABLE_LOCKS */
1495 code = RXAFS_SetVolumeStatus(tc->id, avc->fid.Fid.Volume,
1496 &storeStat, volName, offLineMsg, motd);
1497 #ifdef RX_ENABLE_LOCKS
1499 #endif /* RX_ENABLE_LOCKS */
1504 (afs_Analyze(tc, code, &avc->fid, areq,
1505 AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1506 SHARED_LOCK, (struct cell *)0));
1508 if (code) return code;
1509 /* we are sending parms back to make compat. with prev system. should
1510 change interface later to not ask for current status, just set new status */
1512 bcopy((char *)&volstat, cp, sizeof(VolumeStatus));
1513 cp += sizeof(VolumeStatus);
1514 strcpy(cp, volName);
1515 cp += strlen(volName)+1;
1516 strcpy(cp, offLineMsg);
1517 cp += strlen(offLineMsg)+1;
1519 cp += strlen(motd)+1;
1520 *aoutSize = cp - aout;
1524 static PFlush(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1525 register struct vcache *avc;
1527 struct vrequest *areq;
1530 afs_int32 *aoutSize; /* set this */
1531 struct AFS_UCRED *acred;
1534 AFS_STATCNT(PFlush);
1535 if (!avc) return EINVAL;
1536 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1537 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1539 ObtainWriteLock(&avc->lock,225);
1540 ObtainWriteLock(&afs_xcbhash, 456);
1541 afs_DequeueCallback(avc);
1542 avc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
1543 ReleaseWriteLock(&afs_xcbhash);
1544 /* now find the disk cache entries */
1545 afs_TryToSmush(avc, acred, 1);
1546 osi_dnlc_purgedp(avc);
1547 afs_symhint_inval(avc);
1548 if (avc->linkData && !(avc->states & CCore)) {
1549 afs_osi_Free(avc->linkData, strlen(avc->linkData)+1);
1550 avc->linkData = (char *) 0;
1552 ReleaseWriteLock(&avc->lock);
1553 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
1554 afs_BozonUnlock(&avc->pvnLock, avc);
1559 static PNewStatMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
1562 struct vrequest *areq;
1565 afs_int32 *aoutSize; /* set this */ {
1566 register afs_int32 code;
1567 register struct vcache *tvc;
1568 register struct dcache *tdc;
1569 struct VenusFid tfid;
1571 afs_int32 offset, len, hasatsys=0;
1573 AFS_STATCNT(PNewStatMount);
1574 if (!avc) return EINVAL;
1575 code = afs_VerifyVCache(avc, areq);
1576 if (code) return code;
1577 if (vType(avc) != VDIR) {
1580 tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
1581 if (!tdc) return ENOENT;
1582 hasatsys = Check_AtSys(avc, ain, &bufp, areq);
1583 code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
1588 tfid.Cell = avc->fid.Cell;
1589 tfid.Fid.Volume = avc->fid.Fid.Volume;
1590 afs_PutDCache(tdc); /* we're done with the data */
1591 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
1592 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
1594 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
1601 if (vType(tvc) != VLNK) {
1602 afs_PutVCache(tvc, WRITE_LOCK);
1606 ObtainWriteLock(&tvc->lock,226);
1607 code = afs_HandleLink(tvc, areq);
1609 if (tvc->linkData) {
1610 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1613 /* we have the data */
1614 strcpy(aout, tvc->linkData);
1615 *aoutSize = strlen(tvc->linkData)+1;
1620 ReleaseWriteLock(&tvc->lock);
1621 afs_PutVCache(tvc, WRITE_LOCK);
1623 if (hasatsys) osi_FreeLargeSpace(bufp);
1627 static PGetTokens(avc, afun, areq, ain, aout, ainSize, aoutSize)
1630 struct vrequest *areq;
1633 afs_int32 *aoutSize; /* set this */ {
1634 register struct cell *tcell;
1635 register afs_int32 i;
1636 register struct unixuser *tu;
1641 AFS_STATCNT(PGetTokens);
1642 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1643 return EIO; /* Inappropriate ioctl for device */
1645 /* weird interface. If input parameter is present, it is an integer and
1646 we're supposed to return the parm'th tokens for this unix uid.
1647 If not present, we just return tokens for cell 1.
1648 If counter out of bounds, return EDOM.
1649 If no tokens for the particular cell, return ENOTCONN.
1650 Also, if this mysterious parm is present, we return, along with the
1651 tokens, the primary cell indicator (an afs_int32 0) and the cell name
1652 at the end, in that order.
1654 if (newStyle = (ainSize > 0)) {
1655 bcopy(ain, (char *)&iterator, sizeof(afs_int32));
1657 i = UHash(areq->uid);
1658 ObtainReadLock(&afs_xuser);
1659 for(tu = afs_users[i]; tu; tu=tu->next) {
1661 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1662 if (iterator-- == 0) break; /* are we done yet? */
1666 if (tu->uid == areq->uid && tu->cell == 1) break;
1671 * No need to hold a read lock on each user entry
1675 ReleaseReadLock(&afs_xuser);
1680 if (((tu->states & UHasTokens) == 0) || (tu->ct.EndTimestamp < osi_Time())) {
1681 tu->states |= (UTokensBad | UNeedsReset);
1682 afs_PutUser(tu, READ_LOCK);
1685 /* use iterator for temp */
1687 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1688 if (iterator < 56) iterator = 56; /* # of bytes we're returning */
1689 bcopy((char *)&iterator, cp, sizeof(afs_int32));
1690 cp += sizeof(afs_int32);
1691 bcopy(tu->stp, cp, tu->stLen); /* copy out st */
1693 iterator = sizeof(struct ClearToken);
1694 bcopy((char *)&iterator, cp, sizeof(afs_int32));
1695 cp += sizeof(afs_int32);
1696 bcopy((char *)&tu->ct, cp, sizeof(struct ClearToken));
1697 cp += sizeof(struct ClearToken);
1699 /* put out primary id and cell name, too */
1700 iterator = (tu->states & UPrimary ? 1 : 0);
1701 bcopy((char *)&iterator, cp, sizeof(afs_int32));
1702 cp += sizeof(afs_int32);
1703 tcell = afs_GetCell(tu->cell, READ_LOCK);
1705 strcpy(cp, tcell->cellName);
1706 cp += strlen(tcell->cellName)+1;
1707 afs_PutCell(tcell, READ_LOCK);
1711 *aoutSize = cp - aout;
1712 afs_PutUser(tu, READ_LOCK);
1716 static PUnlog(avc, afun, areq, ain, aout, ainSize, aoutSize)
1719 struct vrequest *areq;
1722 afs_int32 *aoutSize; /* set this */ {
1723 register afs_int32 i;
1724 register struct unixuser *tu;
1726 AFS_STATCNT(PUnlog);
1727 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1728 return EIO; /* Inappropriate ioctl for device */
1730 i = UHash(areq->uid);
1731 ObtainWriteLock(&afs_xuser,227);
1732 for(tu=afs_users[i]; tu; tu=tu->next) {
1733 if (tu->uid == areq->uid) {
1735 tu->states &= ~UHasTokens;
1736 /* security is not having to say you're sorry */
1737 bzero((char *)&tu->ct, sizeof(struct ClearToken));
1739 ReleaseWriteLock(&afs_xuser);
1740 /* We have to drop the lock over the call to afs_ResetUserConns, since
1741 * it obtains the afs_xvcache lock. We could also keep the lock, and
1742 * modify ResetUserConns to take parm saying we obtained the lock
1743 * already, but that is overkill. By keeping the "tu" pointer
1744 * held over the released lock, we guarantee that we won't lose our
1745 * place, and that we'll pass over every user conn that existed when
1746 * we began this call.
1748 afs_ResetUserConns(tu);
1750 ObtainWriteLock(&afs_xuser,228);
1753 ReleaseWriteLock(&afs_xuser);
1757 static PMariner(avc, afun, areq, ain, aout, ainSize, aoutSize)
1760 struct vrequest *areq;
1763 afs_int32 *aoutSize; /* set this */ {
1764 afs_int32 newHostAddr;
1765 afs_int32 oldHostAddr;
1767 AFS_STATCNT(PMariner);
1769 bcopy((char *)&afs_marinerHost, (char *)&oldHostAddr, sizeof(afs_int32));
1771 oldHostAddr = 0xffffffff; /* disabled */
1773 bcopy(ain, (char *)&newHostAddr, sizeof(afs_int32));
1774 if (newHostAddr == 0xffffffff) {
1775 /* disable mariner operations */
1778 else if (newHostAddr) {
1780 afs_marinerHost = newHostAddr;
1782 bcopy((char *)&oldHostAddr, aout, sizeof(afs_int32));
1783 *aoutSize = sizeof(afs_int32);
1787 static PCheckServers(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
1790 struct vrequest *areq;
1793 afs_int32 *aoutSize; /* set this */
1794 struct AFS_UCRED *acred;
1796 register char *cp = 0;
1798 register struct server *ts;
1799 afs_int32 temp, *lp = (afs_int32 *)ain, havecell=0;
1801 struct chservinfo *pcheck;
1803 AFS_STATCNT(PCheckServers);
1805 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1806 return EIO; /* Inappropriate ioctl for device */
1808 if (*lp == 0x12345678) { /* For afs3.3 version */
1809 pcheck=(struct chservinfo *)ain;
1810 if (pcheck->tinterval >= 0) {
1812 bcopy((char *)&PROBE_INTERVAL, cp, sizeof(afs_int32));
1813 *aoutSize = sizeof(afs_int32);
1814 if (pcheck->tinterval > 0) {
1815 if (!afs_osi_suser(acred))
1817 PROBE_INTERVAL=pcheck->tinterval;
1823 temp=pcheck->tflags;
1824 cp = pcheck->tbuffer;
1825 } else { /* For pre afs3.3 versions */
1826 bcopy(ain, (char *)&temp, sizeof(afs_int32));
1827 cp = ain+sizeof(afs_int32);
1828 if (ainSize > sizeof(afs_int32))
1833 * 1: fast check, don't contact servers.
1834 * 2: local cell only.
1837 /* have cell name, too */
1838 cellp = afs_GetCellByName(cp, READ_LOCK);
1839 if (!cellp) return ENOENT;
1841 else cellp = (struct cell *) 0;
1842 if (!cellp && (temp & 2)) {
1843 /* use local cell */
1844 cellp = afs_GetCell(1, READ_LOCK);
1846 if (!(temp & 1)) { /* if not fast, call server checker routine */
1847 afs_CheckServers(1, cellp); /* check down servers */
1848 afs_CheckServers(0, cellp); /* check up servers */
1850 /* now return the current down server list */
1852 ObtainReadLock(&afs_xserver);
1853 for(i=0;i<NSERVERS;i++) {
1854 for(ts = afs_servers[i]; ts; ts=ts->next) {
1855 if (cellp && ts->cell != cellp) continue; /* cell spec'd and wrong */
1856 if ((ts->flags & SRVR_ISDOWN) && ts->addr->sa_portal != ts->cell->vlport) {
1857 bcopy((char *)&ts->addr->sa_ip, cp, sizeof(afs_int32));
1858 cp += sizeof(afs_int32);
1862 ReleaseReadLock(&afs_xserver);
1863 if (cellp) afs_PutCell(cellp, READ_LOCK);
1864 *aoutSize = cp - aout;
1868 static PCheckVolNames(avc, afun, areq, ain, aout, ainSize, aoutSize)
1871 struct vrequest *areq;
1874 afs_int32 *aoutSize; /* set this */ {
1875 AFS_STATCNT(PCheckVolNames);
1876 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1877 return EIO; /* Inappropriate ioctl for device */
1879 afs_CheckRootVolume();
1880 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE |
1881 AFS_VOLCHECK_EXPIRED |
1883 AFS_VOLCHECK_MTPTS);
1887 static PCheckAuth(avc, afun, areq, ain, aout, ainSize, aoutSize)
1890 struct vrequest *areq;
1893 afs_int32 *aoutSize; /* set this */ {
1897 struct unixuser *tu;
1899 extern afs_rwlock_t afs_xsrvAddr;
1901 AFS_STATCNT(PCheckAuth);
1902 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
1903 return EIO; /* Inappropriate ioctl for device */
1906 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
1907 if (!tu) retValue = EACCES;
1909 /* we have a user */
1910 ObtainReadLock(&afs_xsrvAddr);
1911 ObtainReadLock(&afs_xconn);
1913 /* any tokens set? */
1914 if ((tu->states & UHasTokens) == 0) retValue = EACCES;
1915 /* all connections in cell 1 working? */
1916 for(i=0;i<NSERVERS;i++) {
1917 for(sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
1918 for (tc = sa->conns; tc; tc=tc->next) {
1919 if (tc->user == tu && (tu->states & UTokensBad))
1924 ReleaseReadLock(&afs_xsrvAddr);
1925 ReleaseReadLock(&afs_xconn);
1926 afs_PutUser(tu, READ_LOCK);
1928 bcopy((char *)&retValue, aout, sizeof(afs_int32));
1929 *aoutSize = sizeof(afs_int32);
1933 static Prefetch(apath, adata, afollow, acred)
1935 struct afs_ioctl *adata;
1937 struct AFS_UCRED *acred;
1940 register afs_int32 code;
1943 AFS_STATCNT(Prefetch);
1944 if (!apath) return EINVAL;
1945 tp = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
1946 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
1948 osi_FreeSmallSpace(tp);
1951 if (afs_BBusy()) { /* do this as late as possible */
1952 osi_FreeSmallSpace(tp);
1953 return EWOULDBLOCK; /* pretty close */
1955 afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred, (long)tp, 0L, 0L, 0L);
1959 static PFindVolume(avc, afun, areq, ain, aout, ainSize, aoutSize)
1962 struct vrequest *areq;
1965 afs_int32 *aoutSize; /* set this */ {
1966 register struct volume *tvp;
1967 register struct server *ts;
1968 register afs_int32 i;
1971 AFS_STATCNT(PFindVolume);
1972 if (!avc) return EINVAL;
1973 tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
1976 for(i=0;i<MAXHOSTS;i++) {
1977 ts = tvp->serverHost[i];
1979 bcopy((char *)&ts->addr->sa_ip, cp, sizeof(afs_int32));
1980 cp += sizeof(afs_int32);
1983 /* still room for terminating NULL, add it on */
1984 ainSize = 0; /* reuse vbl */
1985 bcopy((char *)&ainSize, cp, sizeof(afs_int32));
1986 cp += sizeof(afs_int32);
1988 *aoutSize = cp - aout;
1989 afs_PutVolume(tvp, READ_LOCK);
1995 static PViceAccess(avc, afun, areq, ain, aout, ainSize, aoutSize)
1998 struct vrequest *areq;
2001 afs_int32 *aoutSize; /* set this */ {
2002 register afs_int32 code;
2005 AFS_STATCNT(PViceAccess);
2006 if (!avc) return EINVAL;
2007 code = afs_VerifyVCache(avc, areq);
2008 if (code) return code;
2009 bcopy(ain, (char *)&temp, sizeof(afs_int32));
2010 code = afs_AccessOK(avc,temp, areq, CHECK_MODE_BITS);
2015 static PSetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2018 struct vrequest *areq;
2021 afs_int32 *aoutSize; /* set this */
2022 struct AFS_UCRED *acred;
2027 AFS_STATCNT(PSetCacheSize);
2028 if (!afs_osi_suser(acred))
2030 /* too many things are setup initially in mem cache version */
2031 if (cacheDiskType == AFS_FCACHE_TYPE_MEM) return EROFS;
2032 bcopy(ain, (char *)&newValue, sizeof(afs_int32));
2033 if (newValue == 0) afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2035 extern u_int afs_min_cache;
2036 if (newValue < afs_min_cache)
2037 afs_cacheBlocks = afs_min_cache;
2039 afs_cacheBlocks = newValue;
2041 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2042 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2043 afs_MaybeWakeupTruncateDaemon();
2044 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2045 afs_osi_Wait(1000, 0, 0);
2046 afs_MaybeWakeupTruncateDaemon();
2051 #define MAXGCSTATS 16
2052 static PGetCacheSize(avc, afun, areq, ain, aout, ainSize, aoutSize)
2055 struct vrequest *areq;
2058 afs_int32 *aoutSize; /* set this */ {
2059 afs_int32 results[MAXGCSTATS];
2061 AFS_STATCNT(PGetCacheSize);
2062 bzero((char *)results, sizeof(results));
2063 results[0] = afs_cacheBlocks;
2064 results[1] = afs_blocksUsed;
2065 bcopy((char *)results, aout, sizeof(results));
2066 *aoutSize = sizeof(results);
2070 static PRemoveCallBack(avc, afun, areq, ain, aout, ainSize, aoutSize)
2073 struct vrequest *areq;
2076 afs_int32 *aoutSize; /* set this */ {
2077 register struct conn *tc;
2078 register afs_int32 code;
2079 struct AFSCallBack CallBacks_Array[1];
2080 struct AFSCBFids theFids;
2081 struct AFSCBs theCBs;
2084 AFS_STATCNT(PRemoveCallBack);
2085 if (!avc) return EINVAL;
2086 if (avc->states & CRO) return 0; /* read-only-ness can't change */
2087 ObtainWriteLock(&avc->lock,229);
2088 theFids.AFSCBFids_len = 1;
2089 theCBs.AFSCBs_len = 1;
2090 theFids.AFSCBFids_val = (struct AFSFid *) &avc->fid.Fid;
2091 theCBs.AFSCBs_val = CallBacks_Array;
2092 CallBacks_Array[0].CallBackType = CB_DROPPED;
2093 if (avc->callback) {
2095 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2097 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2098 #ifdef RX_ENABLE_LOCKS
2100 #endif /* RX_ENABLE_LOCKS */
2101 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2102 #ifdef RX_ENABLE_LOCKS
2104 #endif /* RX_ENABLE_LOCKS */
2107 /* don't set code on failure since we wouldn't use it */
2109 (afs_Analyze(tc, code, &avc->fid, areq,
2110 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS,
2111 SHARED_LOCK, (struct cell *)0));
2113 ObtainWriteLock(&afs_xcbhash, 457);
2114 afs_DequeueCallback(avc);
2116 avc->states &= ~(CStatd | CUnique);
2117 ReleaseWriteLock(&afs_xcbhash);
2118 if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2119 osi_dnlc_purgedp(avc);
2121 ReleaseWriteLock(&avc->lock);
2125 static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2128 struct vrequest *areq;
2132 struct AFS_UCRED *acred;
2133 afs_int32 *aoutSize; /* set this */ {
2134 /* create a new cell */
2135 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic=0;
2136 register struct cell *tcell;
2137 char *newcell=0, *linkedcell=0, *tp= ain;
2138 register afs_int32 code, linkedstate=0, ls;
2139 u_short fsport = 0, vlport = 0;
2142 AFS_STATCNT(PNewCell);
2143 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2144 return EIO; /* Inappropriate ioctl for device */
2146 if (!afs_osi_suser(acred))
2149 bcopy(tp, (char *)&magic, sizeof(afs_int32));
2150 tp += sizeof(afs_int32);
2151 if (magic != 0x12345678)
2154 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2155 * server addresses while the 3.5 fs newcell command passes
2156 * MAXHOSTS. To figure out which is which, check if the cellname
2159 newcell = tp + (MAXCELLHOSTS+3)*sizeof(afs_int32);
2160 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2162 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2163 bcopy(tp, (char *)cellHosts, MAXCELLHOSTS * sizeof(afs_int32));
2164 tp += (scount * sizeof(afs_int32));
2166 lp = (afs_int32 *)tp;
2169 if (fsport < 1024) fsport = 0; /* Privileged ports not allowed */
2170 if (vlport < 1024) vlport = 0; /* Privileged ports not allowed */
2171 tp += (3 * sizeof(afs_int32));
2173 if ((ls = *lp) & 1) {
2174 linkedcell = tp + strlen(newcell)+1;
2175 linkedstate |= CLinkedCell;
2178 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2179 code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport);
2183 static PListCells(avc, afun, areq, ain, aout, ainSize, aoutSize)
2186 struct vrequest *areq;
2189 afs_int32 *aoutSize; /* set this */ {
2190 afs_int32 whichCell;
2191 register struct cell *tcell=0;
2192 register afs_int32 i;
2193 register char *cp, *tp = ain;
2194 register struct afs_q *cq, *tq;
2196 AFS_STATCNT(PListCells);
2197 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2198 return EIO; /* Inappropriate ioctl for device */
2200 bcopy(tp, (char *)&whichCell, sizeof(afs_int32));
2201 tp += sizeof(afs_int32);
2202 ObtainReadLock(&afs_xcell);
2203 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
2204 tcell = QTOC(cq); tq = QNext(cq);
2205 if (whichCell == 0) break;
2206 if (tq == &CellLRU) tcell = 0;
2211 bzero(cp, MAXCELLHOSTS * sizeof(afs_int32));
2212 for(i=0;i<MAXCELLHOSTS;i++) {
2213 if (tcell->cellHosts[i] == 0) break;
2214 bcopy((char *)&tcell->cellHosts[i]->addr->sa_ip, cp, sizeof(afs_int32));
2215 cp += sizeof(afs_int32);
2217 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2218 strcpy(cp, tcell->cellName);
2219 cp += strlen(tcell->cellName)+1;
2220 *aoutSize = cp - aout;
2222 ReleaseReadLock(&afs_xcell);
2223 if (tcell) return 0;
2227 static PRemoveMount(avc, afun, areq, ain, aout, ainSize, aoutSize)
2230 struct vrequest *areq;
2234 afs_int32 *aoutSize; /* set this */ {
2235 register afs_int32 code;
2237 afs_int32 offset, len, hasatsys = 0;
2238 register struct conn *tc;
2239 register struct dcache *tdc;
2240 register struct vcache *tvc;
2241 struct AFSFetchStatus OutDirStatus;
2242 struct VenusFid tfid;
2243 struct AFSVolSync tsync;
2247 /* "ain" is the name of the file in this dir to remove */
2249 AFS_STATCNT(PRemoveMount);
2250 if (!avc) return EINVAL;
2251 code = afs_VerifyVCache(avc, areq);
2252 if (code) return code;
2253 if (vType(avc) != VDIR) return ENOTDIR;
2255 tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1); /* test for error below */
2256 if (!tdc) return ENOENT;
2257 hasatsys = Check_AtSys(avc, ain, &bufp, areq);
2258 code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
2263 tfid.Cell = avc->fid.Cell;
2264 tfid.Fid.Volume = avc->fid.Fid.Volume;
2265 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
2266 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
2268 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0,
2269 (struct vcache*)0/*xxx avc?*/, WRITE_LOCK);
2276 if (vType(tvc) != VLNK) {
2278 afs_PutVCache(tvc, WRITE_LOCK);
2282 ObtainWriteLock(&tvc->lock,230);
2283 code = afs_HandleLink(tvc, areq);
2285 if (tvc->linkData) {
2286 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2291 ReleaseWriteLock(&tvc->lock);
2292 osi_dnlc_purgedp(tvc);
2293 afs_PutVCache(tvc, WRITE_LOCK);
2298 ObtainWriteLock(&avc->lock,231);
2299 osi_dnlc_remove(avc, bufp, tvc);
2301 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
2303 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2304 #ifdef RX_ENABLE_LOCKS
2306 #endif /* RX_ENABLE_LOCKS */
2307 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &avc->fid.Fid,
2308 bufp, &OutDirStatus, &tsync);
2309 #ifdef RX_ENABLE_LOCKS
2311 #endif /* RX_ENABLE_LOCKS */
2316 (afs_Analyze(tc, code, &avc->fid, areq,
2317 AFS_STATS_FS_RPCIDX_REMOVEFILE,
2318 SHARED_LOCK, (struct cell *)0));
2321 if (tdc) afs_PutDCache(tdc);
2322 ReleaseWriteLock(&avc->lock);
2326 /* we have the thing in the cache */
2327 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2328 /* we can do it locally */
2329 code = afs_dir_Delete(&tdc->f.inode, bufp);
2331 ZapDCE(tdc); /* surprise error -- invalid value */
2332 DZap(&tdc->f.inode);
2335 afs_PutDCache(tdc); /* drop ref count */
2337 avc->states &= ~CUnique; /* For the dfs xlator */
2338 ReleaseWriteLock(&avc->lock);
2341 if (hasatsys) osi_FreeLargeSpace(bufp);
2345 static PVenusLogging(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2348 struct vrequest *areq;
2352 struct AFS_UCRED *acred;
2353 afs_int32 *aoutSize; /* set this */ {
2354 return EINVAL; /* OBSOLETE */
2357 static PGetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2360 struct vrequest *areq;
2363 afs_int32 *aoutSize; /* set this */ {
2364 register struct cell *tcell;
2367 AFS_STATCNT(PGetCellStatus);
2368 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2369 return EIO; /* Inappropriate ioctl for device */
2371 tcell = afs_GetCellByName(ain, READ_LOCK);
2372 if (!tcell) return ENOENT;
2373 temp = tcell->states;
2374 afs_PutCell(tcell, READ_LOCK);
2375 bcopy((char *)&temp, aout, sizeof(afs_int32));
2376 *aoutSize = sizeof(afs_int32);
2380 static PSetCellStatus(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2383 struct vrequest *areq;
2386 struct AFS_UCRED *acred;
2387 afs_int32 *aoutSize; /* set this */ {
2388 register struct cell *tcell;
2391 if (!afs_osi_suser(acred))
2393 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2394 return EIO; /* Inappropriate ioctl for device */
2396 tcell = afs_GetCellByName(ain+2*sizeof(afs_int32), WRITE_LOCK);
2397 if (!tcell) return ENOENT;
2398 bcopy(ain, (char *)&temp, sizeof(afs_int32));
2400 tcell->states |= CNoSUID;
2402 tcell->states &= ~CNoSUID;
2403 afs_PutCell(tcell, WRITE_LOCK);
2407 static PFlushVolumeData(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2410 struct vrequest *areq;
2413 afs_int32 *aoutSize; /* set this */
2414 struct AFS_UCRED *acred;
2416 extern struct volume *afs_volumes[NVOLS];
2417 register afs_int32 i;
2418 register struct dcache *tdc;
2419 register struct vcache *tvc;
2420 register struct volume *tv;
2421 afs_int32 cell, volume;
2423 AFS_STATCNT(PFlushVolumeData);
2424 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2425 return EIO; /* Inappropriate ioctl for device */
2427 volume = avc->fid.Fid.Volume; /* who to zap */
2428 cell = avc->fid.Cell;
2431 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2432 * the vcaches associated with the volume.
2434 ObtainReadLock(&afs_xvcache);
2435 for(i = 0; i < VCSIZE; i++) {
2436 for(tvc = afs_vhashT[i]; tvc; tvc=tvc->hnext) {
2437 if (tvc->fid.Fid.Volume == volume && tvc->fid.Cell == cell) {
2438 #if defined(AFS_SGI_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV)
2439 VN_HOLD((struct vnode *)tvc);
2443 ReleaseReadLock(&afs_xvcache);
2444 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2445 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
2447 ObtainWriteLock(&tvc->lock,232);
2449 ObtainWriteLock(&afs_xcbhash, 458);
2450 afs_DequeueCallback(tvc);
2451 tvc->states &= ~(CStatd | CDirty);
2452 ReleaseWriteLock(&afs_xcbhash);
2453 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
2454 osi_dnlc_purgedp(tvc);
2455 afs_TryToSmush(tvc, acred, 1);
2456 ReleaseWriteLock(&tvc->lock);
2457 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
2458 afs_BozonUnlock(&tvc->pvnLock, tvc);
2460 ObtainReadLock(&afs_xvcache);
2461 /* our tvc ptr is still good until now */
2466 ReleaseReadLock(&afs_xvcache);
2469 MObtainWriteLock(&afs_xdcache,328); /* needed if you're going to flush any stuff */
2470 for(i=0;i<afs_cacheFiles;i++) {
2471 if (!(afs_indexFlags[i] & IFEverUsed)) continue; /* never had any data */
2472 tdc = afs_GetDSlot(i, (struct dcache *) 0);
2473 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
2474 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
2475 if (! (afs_indexFlags[i] & IFDataMod)) {
2476 /* if the file is modified, but has a ref cnt of only 1, then
2477 someone probably has the file open and is writing into it.
2478 Better to skip flushing such a file, it will be brought back
2479 immediately on the next write anyway.
2481 If we *must* flush, then this code has to be rearranged to call
2482 afs_storeAllSegments() first */
2483 afs_FlushDCache(tdc);
2487 tdc->refCount--; /* bumped by getdslot */
2489 MReleaseWriteLock(&afs_xdcache);
2491 ObtainReadLock(&afs_xvolume);
2492 for (i=0;i<NVOLS;i++) {
2493 for (tv = afs_volumes[i]; tv; tv=tv->next) {
2494 if (tv->volume == volume) {
2495 afs_ResetVolumeInfo(tv);
2500 ReleaseReadLock(&afs_xvolume);
2502 /* probably, a user is doing this, probably, because things are screwed up.
2503 * maybe it's the dnlc's fault? */
2510 static PGetVnodeXStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
2513 struct vrequest *areq;
2516 afs_int32 *aoutSize; /* set this */ {
2517 register afs_int32 code;
2518 struct vcxstat stat;
2521 /* AFS_STATCNT(PGetVnodeXStatus); */
2522 if (!avc) return EINVAL;
2523 code = afs_VerifyVCache(avc, areq);
2524 if (code) return code;
2525 if (vType(avc) == VDIR)
2526 mode = PRSFS_LOOKUP;
2529 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
2531 stat.fid = avc->fid;
2532 hset32(stat.DataVersion, hgetlo(avc->m.DataVersion));
2533 stat.lock = avc->lock;
2534 stat.parentVnode = avc->parentVnode;
2535 stat.parentUnique = avc->parentUnique;
2536 hset(stat.flushDV, avc->flushDV);
2537 hset(stat.mapDV, avc->mapDV);
2538 stat.truncPos = avc->truncPos;
2539 { /* just grab the first two - won't break anything... */
2540 struct axscache *ac;
2542 for (i=0, ac=avc->Access; ac && i < CPSIZE; i++, ac=ac->next) {
2543 stat.randomUid[i] = ac->uid;
2544 stat.randomAccess[i] = ac->axess;
2547 stat.callback = afs_data_pointer_to_int32(avc->callback);
2548 stat.cbExpires = avc->cbExpires;
2549 stat.anyAccess = avc->anyAccess;
2550 stat.opens = avc->opens;
2551 stat.execsOrWriters = avc->execsOrWriters;
2552 stat.flockCount = avc->flockCount;
2553 stat.mvstat = avc->mvstat;
2554 stat.states = avc->states;
2555 bcopy((char *)&stat, aout, sizeof(struct vcxstat));
2556 *aoutSize = sizeof(struct vcxstat);
2561 /* We require root for local sysname changes, but not for remote */
2562 /* (since we don't really believe remote uids anyway) */
2563 /* outname[] shouldn't really be needed- this is left as an excercise */
2564 /* for the reader. */
2566 static PSetSysName(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2569 struct vrequest *areq;
2572 afs_int32 *aoutSize; /* set this */
2573 register struct AFS_UCRED *acred;
2575 char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
2576 int setsysname, foundname=0;
2577 register struct afs_exporter *exporter;
2578 extern struct unixuser *afs_FindUser();
2579 extern char *afs_sysname;
2580 register struct unixuser *au;
2581 register afs_int32 pag, error;
2585 AFS_STATCNT(PSetSysName);
2586 if (!afs_globalVFS) {
2587 /* Afsd is NOT running; disable it */
2588 #if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SGI64_ENV) || defined(AFS_LINUX22_ENV)
2591 return (setuerror(EINVAL), EINVAL);
2594 bzero(inname, MAXSYSNAME);
2595 bcopy(ain, (char *)&setsysname, sizeof(afs_int32));
2596 ain += sizeof(afs_int32);
2601 bcopy(ain, inname, t+1); /* include terminating null */
2604 if (acred->cr_gid == RMTUSER_REQ) { /* Handles all exporters */
2605 pag = PagInCred(acred);
2607 return EINVAL; /* Better than panicing */
2609 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
2610 return EINVAL; /* Better than panicing */
2612 if (!(exporter = au->exporter)) {
2613 afs_PutUser(au, READ_LOCK);
2614 return EINVAL; /* Better than panicing */
2616 error = EXP_SYSNAME(exporter, (setsysname? inname : (char *)0), outname);
2618 if (error == ENODEV) foundname = 0; /* sysname not set yet! */
2620 afs_PutUser(au, READ_LOCK);
2625 afs_PutUser(au, READ_LOCK);
2627 if (!afs_sysname) osi_Panic("PSetSysName: !afs_sysname\n");
2629 strcpy(outname, afs_sysname);
2632 if (!afs_osi_suser(acred)) /* Local guy; only root can change sysname */
2634 strcpy(afs_sysname, inname);
2639 bcopy((char *)&foundname, cp, sizeof(afs_int32));
2640 cp += sizeof(afs_int32);
2642 strcpy(cp, outname);
2643 cp += strlen(outname)+1;
2645 *aoutSize = cp - aout;
2650 /* sequential search through the list of touched cells is not a good
2651 * long-term solution here. For small n, though, it should be just
2652 * fine. Should consider special-casing the local cell for large n.
2653 * Likewise for PSetSPrefs.
2655 static void ReSortCells(s,l, vlonly)
2656 int s; /* number of ids in array l[] -- NOT index of last id */
2657 afs_int32 l[]; /* array of cell ids which have volumes that need to be sorted */
2658 int vlonly; /* sort vl servers or file servers?*/
2660 extern struct volume *afs_volumes[NVOLS]; /* volume hash table */
2669 tcell = afs_GetCell(l[k], WRITE_LOCK);
2670 if (!tcell) continue;
2671 afs_SortServers(tcell->cellHosts, MAXCELLHOSTS);
2672 afs_PutCell(tcell, WRITE_LOCK);
2677 ObtainReadLock(&afs_xvolume);
2678 for (i= 0; i< NVOLS; i++) {
2679 for (j=afs_volumes[i];j;j=j->next) {
2681 if (j->cell == l[k]) {
2682 ObtainWriteLock(&j->lock,233);
2683 afs_SortServers(j->serverHost, MAXHOSTS);
2684 ReleaseWriteLock(&j->lock);
2689 ReleaseReadLock(&afs_xvolume);
2694 static int afs_setsprefs(sp, num, vlonly)
2697 unsigned int vlonly;
2700 int i,j,k,matches,touchedSize;
2701 struct server *srvr = NULL;
2702 afs_int32 touched[34];
2706 for (k=0; k < num; sp++, k++) {
2708 printf ("sp host=%x, rank=%d\n",sp->host.s_addr, sp->rank);
2711 ObtainReadLock(&afs_xserver);
2713 i = SHash(sp->host.s_addr);
2714 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2715 if (sa->sa_ip == sp->host.s_addr) {
2717 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
2718 || (sa->sa_portal == AFS_FSPORT);
2719 if ((!vlonly && isfs) || (vlonly && !isfs)) {
2726 if (sa && matches) { /* found one! */
2728 printf ("sa ip=%x, ip_rank=%d\n",sa->sa_ip, sa->sa_iprank);
2730 sa->sa_iprank = sp->rank + afs_randomMod15();
2731 afs_SortOneServer(sa->server);
2734 /* if we don't know yet what cell it's in, this is moot */
2735 for (j=touchedSize-1; j>=0 && touched[j] != srvr->cell->cell; j--)
2736 /* is it in our list of touched cells ? */ ;
2737 if (j < 0) { /* no, it's not */
2738 touched[touchedSize++] = srvr->cell->cell;
2739 if (touchedSize >= 32) { /* watch for ovrflow */
2740 ReleaseReadLock(&afs_xserver);
2741 ReSortCells(touchedSize, touched, vlonly);
2743 ObtainReadLock(&afs_xserver);
2749 ReleaseReadLock(&afs_xserver);
2750 /* if we didn't find one, start to create one. */
2751 /* Note that it doesn't have a cell yet... */
2753 afs_uint32 temp = sp->host.s_addr;
2754 srvr = afs_GetServer(&temp, 1, NULL, (vlonly ? AFS_VLPORT : AFS_FSPORT),
2755 WRITE_LOCK, (afsUUID *)0,0);
2756 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
2757 afs_PutServer(srvr, WRITE_LOCK);
2759 } /* for all cited preferences */
2761 ReSortCells(touchedSize, touched, vlonly);
2765 /* Note that this may only be performed by the local root user.
2768 PSetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2771 struct vrequest *areq;
2774 struct AFS_UCRED *acred;
2775 afs_int32 *aoutSize;
2777 struct setspref *ssp;
2778 AFS_STATCNT(PSetSPrefs);
2780 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2781 return EIO; /* Inappropriate ioctl for device */
2783 if (!afs_osi_suser(acred))
2786 if (ainSize < sizeof(struct setspref))
2789 ssp = (struct setspref *)ain;
2790 if (ainSize < sizeof(struct spref)*ssp->num_servers)
2793 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
2794 (ssp->flags & DBservers));
2799 PSetSPrefs33(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2802 struct vrequest *areq;
2805 struct AFS_UCRED *acred;
2806 afs_int32 *aoutSize;
2809 AFS_STATCNT(PSetSPrefs);
2810 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2811 return EIO; /* Inappropriate ioctl for device */
2814 if (!afs_osi_suser(acred))
2817 sp = (struct spref *)ain;
2818 afs_setsprefs(sp, ainSize/(sizeof(struct spref)), 0 /*!vlonly*/);
2822 /* some notes on the following code...
2823 * in the hash table of server structs, all servers with the same IP address
2824 * will be on the same overflow chain.
2825 * This could be sped slightly in some circumstances by having it cache the
2826 * immediately previous slot in the hash table and some supporting information
2827 * Only reports file servers now.
2830 PGetSPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
2833 struct vrequest *areq;
2836 afs_int32 *aoutSize;
2838 struct sprefrequest *spin; /* input */
2839 struct sprefinfo *spout; /* output */
2840 struct spref *srvout; /* one output component */
2841 int i,j; /* counters for hash table traversal */
2842 struct server *srvr; /* one of CM's server structs */
2845 int vlonly; /* just return vlservers ? */
2848 AFS_STATCNT(PGetSPrefs);
2849 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
2850 return EIO; /* Inappropriate ioctl for device */
2853 if (ainSize < sizeof (struct sprefrequest_33)) {
2857 spin = ((struct sprefrequest *) ain);
2860 if (ainSize > sizeof (struct sprefrequest_33)) {
2861 vlonly = (spin->flags & DBservers);
2865 /* struct sprefinfo includes 1 server struct... that size gets added
2866 * in during the loop that follows.
2868 *aoutSize = sizeof(struct sprefinfo) - sizeof (struct spref);
2869 spout = (struct sprefinfo *) aout;
2870 spout->next_offset = spin->offset;
2871 spout->num_servers = 0;
2872 srvout = spout->servers;
2874 ObtainReadLock(&afs_xserver);
2875 for (i=0, j=0; j < NSERVERS; j++) { /* sift through hash table */
2876 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
2877 if (spin->offset > (unsigned short)i) {
2878 continue; /* catch up to where we left off */
2880 spout->next_offset++;
2883 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
2884 || (sa->sa_portal == AFS_FSPORT);
2886 if ((vlonly && isfs) || (!vlonly && !isfs)) {
2887 /* only report ranks for vl servers */
2891 srvout->host.s_addr = sa->sa_ip;
2892 srvout->rank = sa->sa_iprank;
2893 *aoutSize += sizeof(struct spref);
2894 spout->num_servers++;
2897 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
2898 ReleaseReadLock(&afs_xserver); /* no more room! */
2903 ReleaseReadLock(&afs_xserver);
2905 spout->next_offset = 0; /* start over from the beginning next time */
2909 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
2910 int afs_NFSRootOnly = 1;
2911 /*static*/ PExportAfs(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
2914 struct vrequest *areq;
2917 afs_int32 *aoutSize; /* set this */
2918 struct AFS_UCRED *acred;
2920 afs_int32 export, newint=0, type, changestate, handleValue, convmode, pwsync, smounts;
2921 extern struct afs_exporter *exporter_find();
2922 register struct afs_exporter *exporter;
2924 AFS_STATCNT(PExportAfs);
2925 bcopy(ain, (char *)&handleValue, sizeof(afs_int32));
2926 type = handleValue >> 24;
2931 exporter = exporter_find(type);
2933 export = handleValue & 3;
2934 changestate = handleValue & 0xff;
2935 smounts = (handleValue >> 2) & 3;
2936 pwsync = (handleValue >> 4) & 3;
2937 convmode = (handleValue >> 6) & 3;
2939 changestate = (handleValue >> 16) & 0x1;
2940 convmode = (handleValue >> 16) & 0x2;
2941 pwsync = (handleValue >> 16) & 0x4;
2942 smounts = (handleValue >> 16) & 0x8;
2943 export = handleValue & 0xff;
2946 /* Failed finding desired exporter; */
2950 handleValue = exporter->exp_states;
2951 bcopy((char *)&handleValue, aout, sizeof(afs_int32));
2952 *aoutSize = sizeof(afs_int32);
2954 if (!afs_osi_suser(acred))
2955 return EACCES; /* Only superuser can do this */
2959 exporter->exp_states |= EXP_EXPORTED;
2961 exporter->exp_states &= ~EXP_EXPORTED;
2965 exporter->exp_states |= EXP_UNIXMODE;
2967 exporter->exp_states &= ~EXP_UNIXMODE;
2971 exporter->exp_states |= EXP_PWSYNC;
2973 exporter->exp_states &= ~EXP_PWSYNC;
2977 afs_NFSRootOnly = 0;
2978 exporter->exp_states |= EXP_SUBMOUNTS;
2980 afs_NFSRootOnly = 1;
2981 exporter->exp_states &= ~EXP_SUBMOUNTS;
2984 handleValue = exporter->exp_states;
2985 bcopy((char *)&handleValue, aout, sizeof(afs_int32));
2986 *aoutSize = sizeof(afs_int32);
2989 exporter->exp_states |= EXP_EXPORTED;
2991 exporter->exp_states &= ~EXP_EXPORTED;
2993 exporter->exp_states |= EXP_UNIXMODE;
2995 exporter->exp_states &= ~EXP_UNIXMODE;
2997 exporter->exp_states |= EXP_PWSYNC;
2999 exporter->exp_states &= ~EXP_PWSYNC;
3001 afs_NFSRootOnly = 0;
3002 exporter->exp_states |= EXP_SUBMOUNTS;
3004 afs_NFSRootOnly = 1;
3005 exporter->exp_states &= ~EXP_SUBMOUNTS;
3014 PGag(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3017 struct vrequest *areq;
3020 struct AFS_UCRED *acred;
3021 afs_int32 *aoutSize; /* set this */
3023 struct gaginfo *gagflags;
3025 if (!afs_osi_suser(acred))
3028 gagflags = (struct gaginfo *) ain;
3029 afs_showflags = gagflags->showflags;
3036 PTwiddleRx(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3039 struct vrequest *areq;
3042 struct AFS_UCRED *acred;
3043 afs_int32 *aoutSize;
3045 struct rxparams *rxp;
3047 if (!afs_osi_suser(acred))
3050 rxp = (struct rxparams *) ain;
3052 if (rxp->rx_initReceiveWindow)
3053 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3054 if (rxp->rx_maxReceiveWindow)
3055 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3056 if (rxp->rx_initSendWindow)
3057 rx_initSendWindow = rxp->rx_initSendWindow;
3058 if (rxp->rx_maxSendWindow)
3059 rx_maxSendWindow = rxp->rx_maxSendWindow;
3060 if (rxp->rxi_nSendFrags)
3061 rxi_nSendFrags = rxp->rxi_nSendFrags;
3062 if (rxp->rxi_nRecvFrags)
3063 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3064 if (rxp->rxi_OrphanFragSize)
3065 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3066 if (rxp->rx_maxReceiveSize)
3068 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3069 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3071 if (rxp->rx_MyMaxSendSize)
3072 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3077 static int PGetInitParams(avc, afun, areq, ain, aout, ainSize, aoutSize)
3080 struct vrequest *areq;
3084 afs_int32 *aoutSize; /* set this */
3086 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3089 bcopy((char*)&cm_initParams, aout, sizeof(struct cm_initparams));
3090 *aoutSize = sizeof(struct cm_initparams);
3094 #ifdef AFS_SGI65_ENV
3095 /* They took crget() from us, so fake it. */
3096 static cred_t *crget(void)
3099 cr = crdup(get_current_cred());
3100 bzero((char*)cr, sizeof(cred_t));
3101 #if CELL || CELL_PREPARE
3108 * Create new credentials to correspond to a remote user with given
3109 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3110 * provide pioctl (and other) services to foreign clients (i.e. nfs
3111 * clients) by using this call to `become' the client.
3114 #define PIOCTL_HEADER 6
3115 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3118 afs_uint32 hostaddr;
3119 afs_int32 uid, g0, g1, i, code, pag, exporter_type;
3120 extern struct afs_exporter *exporter_find();
3121 struct afs_exporter *exporter, *outexporter;
3122 struct AFS_UCRED *newcred;
3123 struct unixuser *au;
3125 #if defined(AFS_DEC_ENV) || (defined(AFS_NONFSTRANS) && !defined(AFS_AIX_IAUTH_ENV))
3126 return EINVAL; /* NFS trans not supported for Ultrix */
3128 #if defined(AFS_SGIMP_ENV)
3129 osi_Assert(ISAFS_GLOCK());
3131 AFS_STATCNT(HandleClientContext);
3132 if (ablob->in_size < PIOCTL_HEADER*sizeof(afs_int32)) {
3133 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3134 return EINVAL; /* Too small to be good */
3136 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3137 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER*sizeof(afs_int32), code);
3139 osi_FreeLargeSpace(inData);
3143 /* Extract information for remote user */
3144 hostaddr = *((afs_uint32 *)ain);
3145 ain += sizeof(hostaddr);
3146 uid = *((afs_uint32 *)ain);
3148 g0 = *((afs_uint32 *)ain);
3150 g1 = *((afs_uint32 *)ain);
3152 *com = *((afs_uint32 *)ain);
3153 ain += sizeof(afs_int32);
3154 exporter_type = *((afs_uint32 *)ain); /* In case we support more than NFS */
3157 * Of course, one must be root for most of these functions, but
3158 * we'll allow (for knfs) you to set things if the pag is 0 and
3159 * you're setting tokens or unlogging.
3162 if (!afs_osi_suser(credp)) {
3164 #ifndef AFS_SGI64_ENV
3165 /* Since SGI's suser() returns explicit failure after the call.. */
3169 /* check for acceptable opcodes for normal folks, which are, so far,
3170 * set tokens and unlog.
3172 if (i != 9 && i != 3 && i != 38 && i != 8) {
3173 osi_FreeLargeSpace(inData);
3178 ablob->in_size -= PIOCTL_HEADER*sizeof(afs_int32);
3179 ablob->in += PIOCTL_HEADER*sizeof(afs_int32);
3180 osi_FreeLargeSpace(inData);
3183 * We map uid 0 to nobody to match the mapping that the nfs
3184 * server does and to ensure that the suser() calls in the afs
3185 * code fails for remote client roots.
3187 uid = afs_nobody; /* NFS_NOBODY == -2 */
3190 #ifdef AFS_AIX41_ENV
3193 newcred->cr_gid = RMTUSER_REQ;
3194 newcred->cr_groups[0] = g0;
3195 newcred->cr_groups[1] = g1;
3197 newcred->cr_ngrps = 2;
3199 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
3200 newcred->cr_ngroups = 2;
3202 for (i=2; i<NGROUPS; i++)
3203 newcred->cr_groups[i] = NOGROUP;
3206 #if !defined(AFS_OSF_ENV) && !defined(AFS_DEC_ENV)
3207 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
3209 if (!(exporter = exporter_find(exporter_type))) {
3210 /* Exporter wasn't initialized or an invalid exporter type */
3214 if (exporter->exp_states & EXP_PWSYNC) {
3215 if (uid != credp->cr_uid) {
3217 return ENOEXEC; /* XXX Find a better errno XXX */
3220 newcred->cr_uid = uid; /* Only temporary */
3221 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
3222 /* The client's pag is the only unique identifier for it */
3223 newcred->cr_uid = pag;
3225 if (!code && *com == PSETPAG) {
3226 /* Special case for 'setpag' */
3227 afs_uint32 pagvalue = genpag();
3229 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
3231 * Note that we leave the 'outexporter' struct held so it won't
3234 au->exporter = outexporter;
3235 if (ablob->out_size >= 4) {
3236 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32), code);
3238 afs_PutUser(au, WRITE_LOCK);
3239 if (code) return code;
3240 return PSETPAG; /* Special return for setpag */
3242 EXP_RELE(outexporter);
3245 #endif /*defined(AFS_DEC_ENV) || defined(AFS_NONFSTRANS)*/
3248 /* get all interface addresses of this client */
3251 PGetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3254 struct vrequest *areq;
3257 afs_int32 *aoutSize;
3259 struct sprefrequest *spin; /* input */
3260 struct sprefinfo *spout; /* output */
3261 struct spref *srvout; /* one output component */
3265 AFS_STATCNT(PGetCPrefs);
3266 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3267 return EIO; /* Inappropriate ioctl for device */
3269 if ( ainSize < sizeof (struct sprefrequest ))
3272 spin = (struct sprefrequest *) ain;
3273 spout = (struct sprefinfo *) aout;
3275 maxNumber = spin->num_servers; /* max addrs this time */
3276 srvout = spout->servers;
3278 ObtainReadLock(&afs_xinterface);
3280 /* copy out the client interface information from the
3281 ** kernel data structure "interface" to the output buffer
3283 for ( i=spin->offset, j=0; (i < afs_cb_interface.numberOfInterfaces)
3284 && ( j< maxNumber) ; i++, j++, srvout++)
3285 srvout->host.s_addr = afs_cb_interface.addr_in[i];
3287 spout->num_servers = j;
3288 *aoutSize = sizeof(struct sprefinfo) +(j-1)* sizeof (struct spref);
3290 if ( i >= afs_cb_interface.numberOfInterfaces )
3291 spout->next_offset = 0; /* start from beginning again */
3293 spout->next_offset = spin->offset + j;
3295 ReleaseReadLock(&afs_xinterface);
3300 PSetCPrefs(avc, afun, areq, ain, aout, ainSize, aoutSize)
3303 struct vrequest *areq;
3306 afs_int32 *aoutSize;
3308 struct setspref *sin;
3311 AFS_STATCNT(PSetCPrefs);
3312 if ( !afs_resourceinit_flag ) /* afs deamons havn't started yet */
3313 return EIO; /* Inappropriate ioctl for device */
3315 sin = (struct setspref *)ain;
3317 if ( ainSize < sizeof(struct setspref) )
3319 if ( sin->num_servers < 0 )
3321 if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
3324 ObtainWriteLock(&afs_xinterface, 412);
3325 afs_cb_interface.numberOfInterfaces = sin->num_servers;
3326 for ( i=0; (unsigned short)i < sin->num_servers; i++)
3327 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
3329 ReleaseWriteLock(&afs_xinterface);
3333 static PFlushMount(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3336 struct vrequest *areq;
3339 afs_int32 *aoutSize;
3340 struct AFS_UCRED *acred; {
3341 register afs_int32 code;
3342 register struct vcache *tvc;
3343 register struct dcache *tdc;
3344 struct VenusFid tfid;
3346 afs_int32 offset, len, hasatsys=0;
3348 AFS_STATCNT(PFlushMount);
3349 if (!avc) return EINVAL;
3350 code = afs_VerifyVCache(avc, areq);
3351 if (code) return code;
3352 if (vType(avc) != VDIR) {
3355 tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 1);
3356 if (!tdc) return ENOENT;
3357 hasatsys = Check_AtSys(avc, ain, &bufp, areq);
3358 code = afs_dir_Lookup(&tdc->f.inode, bufp, &tfid.Fid);
3363 tfid.Cell = avc->fid.Cell;
3364 tfid.Fid.Volume = avc->fid.Fid.Volume;
3365 afs_PutDCache(tdc); /* we're done with the data */
3366 if (!tfid.Fid.Unique && (avc->states & CForeign)) {
3367 tvc = afs_LookupVCache(&tfid, areq, (afs_int32 *)0, WRITE_LOCK, avc, bufp);
3369 tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache*)0,
3376 if (vType(tvc) != VLNK) {
3377 afs_PutVCache(tvc, WRITE_LOCK);
3381 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3382 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3384 ObtainWriteLock(&tvc->lock,645);
3385 ObtainWriteLock(&afs_xcbhash, 646);
3386 afs_DequeueCallback(tvc);
3387 tvc->states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
3388 ReleaseWriteLock(&afs_xcbhash);
3389 /* now find the disk cache entries */
3390 afs_TryToSmush(tvc, acred, 1);
3391 osi_dnlc_purgedp(tvc);
3392 afs_symhint_inval(tvc);
3393 if (tvc->linkData && !(tvc->states & CCore)) {
3394 afs_osi_Free(tvc->linkData, strlen(tvc->linkData)+1);
3395 tvc->linkData = (char *) 0;
3397 ReleaseWriteLock(&tvc->lock);
3398 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
3399 afs_BozonUnlock(&tvc->pvnLock, tvc);
3401 afs_PutVCache(tvc, WRITE_LOCK);
3403 if (hasatsys) osi_FreeLargeSpace(bufp);
3407 static PRxStatProc(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3410 struct vrequest *areq;
3413 afs_int32 *aoutSize;
3414 struct AFS_UCRED *acred;
3419 if (!afs_osi_suser(acred)) {
3423 if (ainSize != sizeof(afs_int32)) {
3427 bcopy(ain, (char *)&flags, sizeof(afs_int32));
3428 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3432 if (flags & AFSCALL_RXSTATS_ENABLE) {
3433 rx_enableProcessRPCStats();
3435 if (flags & AFSCALL_RXSTATS_DISABLE) {
3436 rx_disableProcessRPCStats();
3438 if (flags & AFSCALL_RXSTATS_CLEAR) {
3439 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
3447 static PRxStatPeer(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
3450 struct vrequest *areq;
3453 afs_int32 *aoutSize;
3454 struct AFS_UCRED *acred;
3459 if (!afs_osi_suser(acred)) {
3463 if (ainSize != sizeof(afs_int32)) {
3467 bcopy(ain, (char *)&flags, sizeof(afs_int32));
3468 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
3472 if (flags & AFSCALL_RXSTATS_ENABLE) {
3473 rx_enablePeerRPCStats();
3475 if (flags & AFSCALL_RXSTATS_DISABLE) {
3476 rx_disablePeerRPCStats();
3478 if (flags & AFSCALL_RXSTATS_CLEAR) {
3479 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);