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"
16 #include "afs/sysincludes.h" /* Standard vendor system headers */
18 #include "h/syscallargs.h"
21 #include "h/sysproto.h"
23 #include "afsincludes.h" /* Afs-based standard headers */
24 #include "afs/afs_stats.h" /* afs statistics */
26 #include "afs/afs_bypasscache.h"
27 #include "rx/rx_globals.h"
29 struct VenusFid afs_rootFid;
30 afs_int32 afs_waitForever = 0;
31 short afs_waitForeverCount = 0;
32 afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
35 afs_int32 afs_is_disconnected;
36 afs_int32 afs_is_discon_rw;
37 /* On reconnection, turn this knob on until it finishes,
40 afs_int32 afs_in_sync = 0;
44 * \defgroup pioctl Path IOCTL functions
46 * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
48 * \param[in] avc the AFS vcache structure in use by pioctl
49 * \param[in] afun not in use
50 * \param[in] areq the AFS vrequest structure
51 * \param[in] ain as defined by the function
52 * \param[in] aout as defined by the function
53 * \param[in] ainSize size of ain
54 * \param[in] aoutSize size of aout
55 * \param[in] acred UNIX credentials structure underlying the operation
58 #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
59 char *ain, char *aout, afs_int32 ainSize, afs_int32 *aoutSize, \
60 struct AFS_UCRED **acred)
62 /* Prototypes for pioctl routines */
65 DECL_PIOCTL(PStoreBehind);
70 DECL_PIOCTL(PGetFileCell);
71 DECL_PIOCTL(PGetWSCell);
72 DECL_PIOCTL(PGetUserCell);
73 DECL_PIOCTL(PSetTokens);
74 DECL_PIOCTL(PGetVolumeStatus);
75 DECL_PIOCTL(PSetVolumeStatus);
77 DECL_PIOCTL(PNewStatMount);
78 DECL_PIOCTL(PGetTokens);
80 DECL_PIOCTL(PMariner);
81 DECL_PIOCTL(PCheckServers);
82 DECL_PIOCTL(PCheckVolNames);
83 DECL_PIOCTL(PCheckAuth);
84 DECL_PIOCTL(PFindVolume);
85 DECL_PIOCTL(PViceAccess);
86 DECL_PIOCTL(PSetCacheSize);
87 DECL_PIOCTL(PGetCacheSize);
88 DECL_PIOCTL(PRemoveCallBack);
89 DECL_PIOCTL(PNewCell);
90 DECL_PIOCTL(PNewAlias);
91 DECL_PIOCTL(PListCells);
92 DECL_PIOCTL(PListAliases);
93 DECL_PIOCTL(PRemoveMount);
94 DECL_PIOCTL(PVenusLogging);
95 DECL_PIOCTL(PGetCellStatus);
96 DECL_PIOCTL(PSetCellStatus);
97 DECL_PIOCTL(PFlushVolumeData);
98 DECL_PIOCTL(PGetVnodeXStatus);
99 DECL_PIOCTL(PGetVnodeXStatus2);
100 DECL_PIOCTL(PSetSysName);
101 DECL_PIOCTL(PSetSPrefs);
102 DECL_PIOCTL(PSetSPrefs33);
103 DECL_PIOCTL(PGetSPrefs);
104 DECL_PIOCTL(PExportAfs);
106 DECL_PIOCTL(PTwiddleRx);
107 DECL_PIOCTL(PGetInitParams);
108 DECL_PIOCTL(PGetRxkcrypt);
109 DECL_PIOCTL(PSetRxkcrypt);
110 DECL_PIOCTL(PGetCPrefs);
111 DECL_PIOCTL(PSetCPrefs);
112 DECL_PIOCTL(PFlushMount);
113 DECL_PIOCTL(PRxStatProc);
114 DECL_PIOCTL(PRxStatPeer);
115 DECL_PIOCTL(PPrefetchFromTape);
116 DECL_PIOCTL(PResidencyCmd);
117 DECL_PIOCTL(PCallBackAddr);
118 DECL_PIOCTL(PDiscon);
119 DECL_PIOCTL(PNFSNukeCreds);
120 DECL_PIOCTL(PNewUuid);
121 DECL_PIOCTL(PPrecache);
122 #if defined(AFS_CACHE_BYPASS)
123 DECL_PIOCTL(PSetCachingThreshold);
124 DECL_PIOCTL(PSetCachingBlkSize);
128 * A macro that says whether we're going to need HandleClientContext().
129 * This is currently used only by the nfs translator.
131 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
132 #define AFS_NEED_CLIENTCONTEXT
135 /* Prototypes for private routines */
136 #ifdef AFS_NEED_CLIENTCONTEXT
137 static int HandleClientContext(struct afs_ioctl *ablob, int *com,
138 struct AFS_UCRED **acred,
139 struct AFS_UCRED *credp);
141 int HandleIoctl(register struct vcache *avc, register afs_int32 acom,
142 struct afs_ioctl *adata);
143 int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
144 register struct afs_ioctl *ablob, int afollow,
145 struct AFS_UCRED **acred);
146 static int Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
147 struct AFS_UCRED *acred);
149 typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
150 char *, char *, afs_int32, afs_int32 *,
151 struct AFS_UCRED **);
153 static pioctlFunction VpioctlSw[] = {
158 PGetVolumeStatus, /* 4 */
159 PSetVolumeStatus, /* 5 */
164 PCheckServers, /* 10 */
165 PCheckVolNames, /* 11 */
167 PBogus, /* 13 -- used to be quick check time */
168 PFindVolume, /* 14 */
169 PBogus, /* 15 -- prefetch is now special-cased; see pioctl code! */
170 PBogus, /* 16 -- used to be testing code */
171 PNoop, /* 17 -- used to be enable group */
172 PNoop, /* 18 -- used to be disable group */
173 PBogus, /* 19 -- used to be list group */
174 PViceAccess, /* 20 */
175 PUnlog, /* 21 -- unlog *is* unpag in this system */
176 PGetFID, /* 22 -- get file ID */
177 PBogus, /* 23 -- used to be waitforever */
178 PSetCacheSize, /* 24 */
179 PRemoveCallBack, /* 25 -- flush only the callback */
182 PRemoveMount, /* 28 -- delete mount point */
183 PNewStatMount, /* 29 -- new style mount point stat */
184 PGetFileCell, /* 30 -- get cell name for input file */
185 PGetWSCell, /* 31 -- get cell name for workstation */
186 PMariner, /* 32 - set/get mariner host */
187 PGetUserCell, /* 33 -- get cell name for user */
188 PVenusLogging, /* 34 -- Enable/Disable logging */
189 PGetCellStatus, /* 35 */
190 PSetCellStatus, /* 36 */
191 PFlushVolumeData, /* 37 -- flush all data from a volume */
192 PSetSysName, /* 38 - Set system name */
193 PExportAfs, /* 39 - Export Afs to remote nfs clients */
194 PGetCacheSize, /* 40 - get cache size and usage */
195 PGetVnodeXStatus, /* 41 - get vcache's special status */
196 PSetSPrefs33, /* 42 - Set CM Server preferences... */
197 PGetSPrefs, /* 43 - Get CM Server preferences... */
198 PGag, /* 44 - turn off/on all CM messages */
199 PTwiddleRx, /* 45 - adjust some RX params */
200 PSetSPrefs, /* 46 - Set CM Server preferences... */
201 PStoreBehind, /* 47 - set degree of store behind to be done */
202 PGCPAGs, /* 48 - disable automatic pag gc-ing */
203 PGetInitParams, /* 49 - get initial cm params */
204 PGetCPrefs, /* 50 - get client interface addresses */
205 PSetCPrefs, /* 51 - set client interface addresses */
206 PFlushMount, /* 52 - flush mount symlink data */
207 PRxStatProc, /* 53 - control process RX statistics */
208 PRxStatPeer, /* 54 - control peer RX statistics */
209 PGetRxkcrypt, /* 55 -- Get rxkad encryption flag */
210 PSetRxkcrypt, /* 56 -- Set rxkad encryption flag */
211 PBogus, /* 57 -- arla: set file prio */
212 PBogus, /* 58 -- arla: fallback getfh */
213 PBogus, /* 59 -- arla: fallback fhopen */
214 PBogus, /* 60 -- arla: controls xfsdebug */
215 PBogus, /* 61 -- arla: controls arla debug */
216 PBogus, /* 62 -- arla: debug interface */
217 PBogus, /* 63 -- arla: print xfs status */
218 PBogus, /* 64 -- arla: force cache check */
219 PBogus, /* 65 -- arla: break callback */
220 PPrefetchFromTape, /* 66 -- MR-AFS: prefetch file from tape */
221 PResidencyCmd, /* 67 -- MR-AFS: generic commnd interface */
222 PBogus, /* 68 -- arla: fetch stats */
223 PGetVnodeXStatus2, /* 69 - get caller access and some vcache status */
226 static pioctlFunction CpioctlSw[] = {
228 PNewAlias, /* 1 -- create new cell alias */
229 PListAliases, /* 2 -- list cell aliases */
230 PCallBackAddr, /* 3 -- request addr for callback rxcon */
232 PDiscon, /* 5 -- get/set discon mode */
242 static int (*(OpioctlSw[])) () = {
244 PNFSNukeCreds, /* 1 -- nuke all creds for NFS client */
245 #if defined(AFS_CACHE_BYPASS)
246 PSetCachingThreshold /* 2 -- get/set cache-bypass size threshold */
248 PNoop /* 2 -- get/set cache-bypass size threshold */
252 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
253 int afs_nobody = NFS_NOBODY;
256 HandleIoctl(register struct vcache *avc, register afs_int32 acom,
257 struct afs_ioctl *adata)
259 register afs_int32 code;
262 AFS_STATCNT(HandleIoctl);
264 switch (acom & 0xff) {
266 avc->f.states |= CSafeStore;
268 /* SXW - Should we force a MetaData flush for this flag setting */
271 /* case 2 used to be abort store, but this is no longer provided,
272 * since it is impossible to implement under normal Unix.
276 /* return the name of the cell this file is open on */
277 register struct cell *tcell;
278 register afs_int32 i;
280 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
282 i = strlen(tcell->cellName) + 1; /* bytes to copy out */
284 if (i > adata->out_size) {
285 /* 0 means we're not interested in the output */
286 if (adata->out_size != 0)
290 AFS_COPYOUT(tcell->cellName, adata->out, i, code);
292 afs_PutCell(tcell, READ_LOCK);
298 case 49: /* VIOC_GETINITPARAMS */
299 if (adata->out_size < sizeof(struct cm_initparams)) {
302 AFS_COPYOUT(&cm_initParams, adata->out,
303 sizeof(struct cm_initparams), code);
315 return code; /* so far, none implemented */
320 /* For aix we don't temporarily bypass ioctl(2) but rather do our
321 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
322 * is now called from afs_gn_ioctl.
325 afs_ioctl(struct vcache *tvc, int cmd, int arg)
327 struct afs_ioctl data;
330 AFS_STATCNT(afs_ioctl);
331 if (((cmd >> 8) & 0xff) == 'V') {
332 /* This is a VICEIOCTL call */
333 AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
336 error = HandleIoctl(tvc, cmd, &data);
339 /* No-op call; just return. */
343 #endif /* AFS_AIX_ENV */
345 #if defined(AFS_SGI_ENV)
346 afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
349 , struct vopbd * vbds
353 struct afs_ioctl data;
359 AFS_STATCNT(afs_ioctl);
360 if (((cmd >> 8) & 0xff) == 'V') {
361 /* This is a VICEIOCTL call */
362 error = copyin_afs_ioctl(arg, &data);
365 locked = ISAFS_GLOCK();
368 error = HandleIoctl(tvc, cmd, &data);
373 /* No-op call; just return. */
377 #endif /* AFS_SGI_ENV */
379 /* unlike most calls here, this one uses u.u_error to return error conditions,
380 since this is really an intercepted chapter 2 call, rather than a vnode
383 /* AFS_HPUX102 and up uses VNODE ioctl instead */
384 #if !defined(AFS_HPUX102_ENV) && !defined(AFS_DARWIN80_ENV)
385 #if !defined(AFS_SGI_ENV)
390 kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
392 #else /* __64BIT__ */
394 kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
396 #endif /* __64BIT__ */
399 kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
408 } u_uap, *uap = &u_uap;
410 #if defined(AFS_SUN5_ENV)
412 struct afs_ioctl_sys {
419 afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
421 #elif defined(AFS_OSF_ENV)
423 afs_xioctl(struct proc *p, void *args, long *retval)
429 } *uap = (struct a *)args;
430 #elif defined(AFS_FBSD50_ENV)
433 afs_xioctl(struct thread *td, register struct ioctl_args *uap,
436 struct proc *p = td->td_proc;
437 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
445 afs_xioctl(struct proc *p, register struct ioctl_args *uap, register_t *retval)
447 #elif defined(AFS_LINUX22_ENV)
448 struct afs_ioctl_sys {
453 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
456 struct afs_ioctl_sys ua, *uap = &ua;
465 } *uap = (struct a *)u.u_ap;
466 #endif /* AFS_SUN5_ENV */
468 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
470 #elif !defined(AFS_LINUX22_ENV)
471 register struct file *fd;
473 #if defined(AFS_XBSD_ENV)
474 register struct filedesc *fdp;
476 register struct vcache *tvc;
477 register int ioctlDone = 0, code = 0;
479 AFS_STATCNT(afs_xioctl);
480 #if defined(AFS_DARWIN_ENV)
481 if ((code = fdgetf(p, uap->fd, &fd)))
483 #elif defined(AFS_XBSD_ENV)
485 if ((u_int) uap->fd >= fdp->fd_nfiles
486 || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
488 if ((fd->f_flag & (FREAD | FWRITE)) == 0)
490 #elif defined(AFS_LINUX22_ENV)
493 #elif defined(AFS_AIX32_ENV)
501 if (setuerror(getf(uap->fd, &fd))) {
504 #elif defined(AFS_OSF_ENV)
506 if (code = getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state))
508 #elif defined(AFS_SUN5_ENV)
509 # if defined(AFS_SUN57_ENV)
513 # elif defined(AFS_SUN54_ENV)
518 if (code = getf(uap->fd, &fd)) {
521 # endif /* AFS_SUN57_ENV */
527 /* first determine whether this is any sort of vnode */
528 #if defined(AFS_LINUX22_ENV)
533 if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
535 if (fd->f_type == DTYPE_VNODE) {
537 /* good, this is a vnode; next see if it is an AFS vnode */
538 #if defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV)
539 tvc = VTOAFS(fd->f_vnode); /* valid, given a vnode */
540 #elif defined(AFS_OBSD_ENV)
542 IsAfsVnode((struct vnode *)fd->
543 f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
545 tvc = VTOAFS((struct vnode *)fd->f_data); /* valid, given a vnode */
547 #endif /* AFS_LINUX22_ENV */
548 if (tvc && IsAfsVnode(AFSTOV(tvc))) {
549 /* This is an AFS vnode */
550 if (((uap->com >> 8) & 0xff) == 'V') {
551 register struct afs_ioctl *datap;
554 (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
555 code=copyin_afs_ioctl((char *)uap->arg, datap);
557 osi_FreeSmallSpace(datap);
559 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
562 #if defined(AFS_SUN5_ENV)
577 #else /* AFS_OSF_ENV */
581 #ifdef AFS_LINUX22_ENV
591 code = HandleIoctl(tvc, uap->com, datap);
592 osi_FreeSmallSpace(datap);
606 #if defined(AFS_LINUX22_ENV)
618 code = okioctl(fdes, com, arg, ext, arg2, arg3);
619 #else /* __64BIT__ */
620 code = okioctl32(fdes, com, arg, ext, arg2, arg3);
621 #endif /* __64BIT__ */
622 #else /* !AFS_AIX51_ENV */
623 code = okioctl(fdes, com, arg, ext);
624 #endif /* AFS_AIX51_ENV */
626 #else /* !AFS_AIX41_ENV */
628 okioctl(fdes, com, arg, ext);
629 #elif defined(AFS_SUN5_ENV)
630 #if defined(AFS_SUN57_ENV)
632 #elif defined(AFS_SUN54_ENV)
637 code = ioctl(uap, rvp);
638 #elif defined(AFS_FBSD50_ENV)
639 return ioctl(td, uap);
640 #elif defined(AFS_FBSD_ENV)
641 return ioctl(p, uap);
642 #elif defined(AFS_OBSD_ENV)
643 code = sys_ioctl(p, uap, retval);
644 #elif defined(AFS_DARWIN_ENV)
645 return ioctl(p, uap, retval);
646 #elif defined(AFS_OSF_ENV)
647 code = ioctl(p, args, retval);
654 #elif !defined(AFS_LINUX22_ENV)
668 #ifdef AFS_LINUX22_ENV
671 #if defined(KERNEL_HAVE_UERROR)
674 #if defined(AFS_AIX32_ENV) && !defined(AFS_AIX41_ENV)
675 return (getuerror()? -1 : u.u_ioctlrv);
677 return getuerror()? -1 : 0;
680 #endif /* AFS_LINUX22_ENV */
681 #endif /* AFS_SUN5_ENV */
682 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
686 #endif /* AFS_SGI_ENV */
687 #endif /* AFS_HPUX102_ENV */
689 #if defined(AFS_SGI_ENV)
690 /* "pioctl" system call entry point; just pass argument to the parameterized
699 afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
703 AFS_STATCNT(afs_pioctl);
705 code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
714 #elif defined(AFS_OSF_ENV)
715 afs_pioctl(struct proc *p, void *args, int *retval)
722 } *uap = (struct a *)args;
724 AFS_STATCNT(afs_pioctl);
725 return (afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow));
728 #elif defined(AFS_FBSD50_ENV)
730 afs_pioctl(struct thread *td, void *args, int *retval)
737 } *uap = (struct a *)args;
739 AFS_STATCNT(afs_pioctl);
740 return (afs_syscall_pioctl
741 (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
744 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
746 afs_pioctl(struct proc *p, void *args, int *retval)
753 } *uap = (struct a *)args;
755 AFS_STATCNT(afs_pioctl);
756 #ifdef AFS_DARWIN80_ENV
757 return (afs_syscall_pioctl
758 (uap->path, uap->cmd, uap->cmarg, uap->follow,
761 return (afs_syscall_pioctl
762 (uap->path, uap->cmd, uap->cmarg, uap->follow,
763 p->p_cred->pc_ucred));
769 /* macro to avoid adding any more #ifdef's to pioctl code. */
770 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
771 #define PIOCTL_FREE_CRED() crfree(credp)
773 #define PIOCTL_FREE_CRED()
778 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
779 rval_t *vvp, struct AFS_UCRED *credp)
781 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
782 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
783 struct AFS_UCRED *credp)
785 afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
789 struct afs_ioctl data;
790 #ifdef AFS_NEED_CLIENTCONTEXT
791 struct AFS_UCRED *tmpcred = NULL;
793 struct AFS_UCRED *foreigncreds = NULL;
794 register afs_int32 code = 0;
795 struct vnode *vp = NULL;
797 struct ucred *credp = crref(); /* don't free until done! */
799 #ifdef AFS_LINUX22_ENV
800 cred_t *credp = crref(); /* don't free until done! */
804 AFS_STATCNT(afs_syscall_pioctl);
806 follow = 1; /* compat. with old venus */
807 code = copyin_afs_ioctl(cmarg, &data);
810 #if defined(KERNEL_HAVE_UERROR)
815 if ((com & 0xff) == PSetClientContext) {
816 #ifdef AFS_NEED_CLIENTCONTEXT
817 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
818 code = HandleClientContext(&data, &com, &foreigncreds, credp);
820 code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
824 crfree(foreigncreds);
827 #if defined(KERNEL_HAVE_UERROR)
828 return (setuerror(code), code);
833 #else /* AFS_NEED_CLIENTCONTEXT */
835 #endif /* AFS_NEED_CLIENTCONTEXT */
837 #ifdef AFS_NEED_CLIENTCONTEXT
840 * We could have done without temporary setting the u.u_cred below
841 * (foreigncreds could be passed as param the pioctl modules)
842 * but calls such as afs_osi_suser() doesn't allow that since it
843 * references u.u_cred directly. We could, of course, do something
844 * like afs_osi_suser(cred) which, I think, is better since it
845 * generalizes and supports multi cred environments...
847 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
849 credp = foreigncreds;
850 #elif defined(AFS_AIX41_ENV)
851 tmpcred = crref(); /* XXX */
853 #elif defined(AFS_HPUX101_ENV)
854 tmpcred = p_cred(u.u_procp);
855 set_p_cred(u.u_procp, foreigncreds);
856 #elif defined(AFS_SGI_ENV)
857 tmpcred = OSI_GET_CURRENT_CRED();
858 OSI_SET_CURRENT_CRED(foreigncreds);
861 u.u_cred = foreigncreds;
864 #endif /* AFS_NEED_CLIENTCONTEXT */
865 if ((com & 0xff) == 15) {
866 /* special case prefetch so entire pathname eval occurs in helper process.
867 * otherwise, the pioctl call is essentially useless */
868 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
870 Prefetch(path, &data, follow,
871 foreigncreds ? foreigncreds : credp);
873 code = Prefetch(path, &data, follow, osi_curcred());
876 #if defined(KERNEL_HAVE_UERROR)
885 lookupname(path, USR, follow, NULL, &vp,
886 foreigncreds ? foreigncreds : credp);
888 #ifdef AFS_LINUX22_ENV
889 code = gop_lookupname(path, AFS_UIOUSER, follow, &dp);
891 vp = (struct vnode *)dp->d_inode;
893 code = gop_lookupname(path, AFS_UIOUSER, follow, &vp);
894 #endif /* AFS_LINUX22_ENV */
895 #endif /* AFS_AIX41_ENV */
899 #if defined(KERNEL_HAVE_UERROR)
907 #if defined(AFS_SUN510_ENV)
908 if (vp && !IsAfsVnode(vp)) {
909 struct vnode *realvp;
911 #ifdef AFS_SUN511_ENV
912 (VOP_REALVP(vp, &realvp, NULL) == 0)
914 (VOP_REALVP(vp, &realvp) == 0)
917 struct vnode *oldvp = vp;
925 /* now make the call if we were passed no file, or were passed an AFS file */
926 if (!vp || IsAfsVnode(vp)) {
927 #if defined(AFS_SUN5_ENV)
928 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
929 #elif defined(AFS_AIX41_ENV)
931 struct ucred *cred1, *cred2;
934 cred1 = cred2 = foreigncreds;
936 cred1 = cred2 = credp;
938 code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
939 if (cred1 != cred2) {
940 /* something changed the creds */
944 #elif defined(AFS_HPUX101_ENV)
946 struct ucred *cred = p_cred(u.u_procp);
947 code = afs_HandlePioctl(vp, com, &data, follow, &cred);
949 #elif defined(AFS_SGI_ENV)
952 credp = OSI_GET_CURRENT_CRED();
953 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
955 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
956 code = afs_HandlePioctl(vp, com, &data, follow, &credp);
958 code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
961 #if defined(KERNEL_HAVE_UERROR)
964 code = EINVAL; /* not in /afs */
969 #if defined(AFS_NEED_CLIENTCONTEXT)
972 crset(tmpcred); /* restore original credentials */
974 #if defined(AFS_HPUX101_ENV)
975 set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
976 #elif defined(AFS_SGI_ENV)
977 OSI_SET_CURRENT_CRED(tmpcred); /* restore original credentials */
978 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
979 credp = tmpcred; /* restore original credentials */
981 osi_curcred() = tmpcred; /* restore original credentials */
982 #endif /* AFS_HPUX101_ENV */
983 crfree(foreigncreds);
986 #endif /* AFS_NEED_CLIENTCONTEXT */
988 #ifdef AFS_LINUX22_ENV
991 AFS_RELE(vp); /* put vnode back */
995 #if defined(KERNEL_HAVE_UERROR)
998 return (getuerror());
1004 #define MAXPIOCTLTOKENLEN \
1005 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1008 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
1009 register struct afs_ioctl *ablob, int afollow,
1010 struct AFS_UCRED **acred)
1013 struct vrequest treq;
1014 register afs_int32 code;
1015 register afs_int32 function, device;
1016 afs_int32 inSize, outSize, outSizeMax;
1017 char *inData, *outData;
1018 pioctlFunction *pioctlSw;
1020 struct afs_fakestat_state fakestate;
1022 avc = avp ? VTOAFS(avp) : NULL;
1023 afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
1024 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
1025 AFS_STATCNT(HandlePioctl);
1026 if ((code = afs_InitReq(&treq, *acred)))
1028 afs_InitFakeStat(&fakestate);
1030 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
1032 afs_PutFakeStat(&fakestate);
1036 device = (acom & 0xff00) >> 8;
1038 case 'V': /* Original pioctls */
1039 pioctlSw = VpioctlSw;
1040 pioctlSwSize = sizeof(VpioctlSw);
1042 case 'C': /* Coordinated/common pioctls */
1043 pioctlSw = CpioctlSw;
1044 pioctlSwSize = sizeof(CpioctlSw);
1046 case 'O': /* Coordinated/common pioctls */
1047 pioctlSw = OpioctlSw;
1048 pioctlSwSize = sizeof(OpioctlSw);
1051 afs_PutFakeStat(&fakestate);
1054 function = acom & 0xff;
1055 if (function >= (pioctlSwSize / sizeof(char *))) {
1056 afs_PutFakeStat(&fakestate);
1057 return EINVAL; /* out of range */
1059 inSize = ablob->in_size;
1061 /* Do all range checking before continuing */
1062 if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
1065 /* Note that we use osi_Alloc for large allocs and osi_AllocLargeSpace for small ones */
1066 if (inSize > AFS_LRALLOCSIZ) {
1067 inData = osi_Alloc(inSize + 1);
1069 inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1074 AFS_COPYIN(ablob->in, inData, inSize, code);
1075 inData[inSize] = '\0';
1079 if (inSize > AFS_LRALLOCSIZ) {
1080 osi_Free(inData, inSize + 1);
1082 osi_FreeLargeSpace(inData);
1084 afs_PutFakeStat(&fakestate);
1087 if (function == 8 && device == 'V') { /* PGetTokens */
1088 outSizeMax = MAXPIOCTLTOKENLEN;
1089 outData = osi_Alloc(outSizeMax);
1091 outSizeMax = AFS_LRALLOCSIZ;
1092 outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
1095 if (inSize > AFS_LRALLOCSIZ) {
1096 osi_Free(inData, inSize + 1);
1098 osi_FreeLargeSpace(inData);
1100 afs_PutFakeStat(&fakestate);
1105 (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
1107 if (inSize > AFS_LRALLOCSIZ) {
1108 osi_Free(inData, inSize + 1);
1110 osi_FreeLargeSpace(inData);
1112 if (code == 0 && ablob->out_size > 0) {
1113 if (outSize > ablob->out_size) {
1114 code = E2BIG; /* data wont fit in user buffer */
1115 } else if (outSize) {
1116 AFS_COPYOUT(outData, ablob->out, outSize, code);
1119 if (outSizeMax > AFS_LRALLOCSIZ) {
1120 osi_Free(outData, outSizeMax);
1122 osi_FreeLargeSpace(outData);
1124 afs_PutFakeStat(&fakestate);
1125 return afs_CheckCode(code, &treq, 41);
1129 * VIOCGETFID (22) - Get file ID quickly
1133 * \param[in] ain not in use
1134 * \param[out] aout fid of requested file
1136 * \retval EINVAL Error if some of the initial arguments aren't set
1138 * \post get the file id of some file
1140 DECL_PIOCTL(PGetFID)
1142 AFS_STATCNT(PGetFID);
1145 memcpy(aout, (char *)&avc->f.fid, sizeof(struct VenusFid));
1146 *aoutSize = sizeof(struct VenusFid);
1151 * VIOCSETAL (1) - Set access control list
1155 * \param[in] ain the ACL being set
1156 * \param[out] aout the ACL being set returned
1158 * \retval EINVAL Error if some of the standard args aren't set
1160 * \post Changed ACL, via direct writing to the wire
1162 int dummy_PSetAcl(char *ain, char *aout)
1167 DECL_PIOCTL(PSetAcl)
1169 register afs_int32 code;
1170 struct afs_conn *tconn;
1171 struct AFSOpaque acl;
1172 struct AFSVolSync tsync;
1173 struct AFSFetchStatus OutStatus;
1176 AFS_STATCNT(PSetAcl);
1179 if ((acl.AFSOpaque_len = strlen(ain) + 1) > 1024 /* AFSOPAQUEMAX */)
1182 acl.AFSOpaque_val = ain;
1184 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1186 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
1189 RXAFS_StoreACL(tconn->id, (struct AFSFid *)&avc->f.fid.Fid,
1190 &acl, &OutStatus, &tsync);
1195 } while (afs_Analyze
1196 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
1197 SHARED_LOCK, NULL));
1199 /* now we've forgotten all of the access info */
1200 ObtainWriteLock(&afs_xcbhash, 455);
1202 afs_DequeueCallback(avc);
1203 avc->f.states &= ~(CStatd | CUnique);
1204 ReleaseWriteLock(&afs_xcbhash);
1205 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
1206 osi_dnlc_purgedp(avc);
1208 /* SXW - Should we flush metadata here? */
1212 int afs_defaultAsynchrony = 0;
1215 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1219 * \param[in] ain sbstruct (store behind structure) input
1220 * \param[out] aout resulting sbstruct
1222 * \retval EPERM Error if the user doesn't have super-user credentials
1223 * \retval EACCES Error if there isn't enough access to not check the mode bits
1225 * \post sets asynchrony based on a file, from a struct sbstruct "I THINK"
1227 DECL_PIOCTL(PStoreBehind)
1230 struct sbstruct *sbr;
1232 sbr = (struct sbstruct *)ain;
1233 if (sbr->sb_default != -1) {
1234 if (afs_osi_suser(*acred))
1235 afs_defaultAsynchrony = sbr->sb_default;
1240 if (avc && (sbr->sb_thisfile != -1)) {
1242 (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
1243 avc->asynchrony = sbr->sb_thisfile;
1248 *aoutSize = sizeof(struct sbstruct);
1249 sbr = (struct sbstruct *)aout;
1250 sbr->sb_default = afs_defaultAsynchrony;
1252 sbr->sb_thisfile = avc->asynchrony;
1259 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1263 * \param[in] ain not in use
1264 * \param[out] aout not in use
1266 * \retval EACCES Error if the user doesn't have super-user credentials
1268 * \post set the gcpags to GCPAGS_USERDISABLED
1270 DECL_PIOCTL(PGCPAGs)
1272 if (!afs_osi_suser(*acred)) {
1275 afs_gcpags = AFS_GCPAGS_USERDISABLED;
1280 * VIOCGETAL (2) - Get access control list
1284 * \param[in] ain not in use
1285 * \param[out] aout the ACL
1287 * \retval EINVAL Error if some of the standard args aren't set
1288 * \retval ERANGE Error if the vnode of the file id is too large
1289 * \retval -1 Error if getting the ACL failed
1291 * \post Obtain the ACL, based on file ID
1293 * \notes there is a hack to tell which type of ACL is being returned, checks the top 2-bytes to judge what type of ACL it is, only for dfs xlat or ACLs
1295 DECL_PIOCTL(PGetAcl)
1297 struct AFSOpaque acl;
1298 struct AFSVolSync tsync;
1299 struct AFSFetchStatus OutStatus;
1301 struct afs_conn *tconn;
1305 AFS_STATCNT(PGetAcl);
1308 Fid.Volume = avc->f.fid.Fid.Volume;
1309 Fid.Vnode = avc->f.fid.Fid.Vnode;
1310 Fid.Unique = avc->f.fid.Fid.Unique;
1311 if (avc->f.states & CForeign) {
1313 * For a dfs xlator acl we have a special hack so that the
1314 * xlator will distinguish which type of acl will return. So
1315 * we currently use the top 2-bytes (vals 0-4) to tell which
1316 * type of acl to bring back. Horrible hack but this will
1317 * cause the least number of changes to code size and interfaces.
1319 if (Fid.Vnode & 0xc0000000)
1321 Fid.Vnode |= (ainSize << 30);
1323 acl.AFSOpaque_val = aout;
1325 tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1328 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
1330 code = RXAFS_FetchACL(tconn->id, &Fid, &acl, &OutStatus, &tsync);
1335 } while (afs_Analyze
1336 (tconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
1337 SHARED_LOCK, NULL));
1340 *aoutSize = (acl.AFSOpaque_len == 0 ? 1 : acl.AFSOpaque_len);
1346 * PNoop returns success. Used for functions which are not implemented or are no longer in use.
1350 * \notes Functions involved in this: 17 (VIOCENGROUP) -- used to be enable group; 18 (VIOCDISGROUP) -- used to be disable group; 2 (?) -- get/set cache-bypass size threshold
1359 * PBogus returns fail. Used for functions which are not implemented or are no longer in use.
1363 * \retval EINVAL Error if some of the standard args aren't set
1365 * \notes Functions involved in this: 0 (?); 4 (?); 6 (?); 7 (VIOCSTAT); 8 (?); 13 (VIOCGETTIME) -- used to be quick check time; 15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!; 16 (VIOCNOP) -- used to be testing code; 19 (VIOCLISTGROUPS) -- used to be list group; 23 (VIOCWAITFOREVER) -- used to be waitforever; 57 (VIOC_FPRIOSTATUS) -- arla: set file prio; 58 (VIOC_FHGET) -- arla: fallback getfh; 59 (VIOC_FHOPEN) -- arla: fallback fhopen; 60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug; 61 (VIOC_ARLADEBUG) -- arla: controls arla debug; 62 (VIOC_AVIATOR) -- arla: debug interface; 63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status; 64 (VIOC_CALCULATE_CACHE) -- arla: force cache check; 65 (VIOC_BREAKCELLBACK) -- arla: break callback; 68 (?) -- arla: fetch stats;
1369 AFS_STATCNT(PBogus);
1374 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1378 * \param[in] ain not in use (avc used to pass in file id)
1379 * \param[out] aout cell name
1381 * \retval EINVAL Error if some of the standard args aren't set
1382 * \retval ESRCH Error if the file isn't part of a cell
1384 * \post Get a cell based on a passed in file id
1386 DECL_PIOCTL(PGetFileCell)
1388 register struct cell *tcell;
1390 AFS_STATCNT(PGetFileCell);
1393 tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
1396 strcpy(aout, tcell->cellName);
1397 afs_PutCell(tcell, READ_LOCK);
1398 *aoutSize = strlen(aout) + 1;
1403 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1407 * \param[in] ain not in use
1408 * \param[out] aout cell name
1410 * \retval EIO Error if the afs daemon hasn't started yet
1411 * \retval ESRCH Error if the machine isn't part of a cell, for whatever reason
1413 * \post Get the primary cell that the machine is a part of.
1415 DECL_PIOCTL(PGetWSCell)
1417 struct cell *tcell = NULL;
1419 AFS_STATCNT(PGetWSCell);
1420 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1421 return EIO; /* Inappropriate ioctl for device */
1423 tcell = afs_GetPrimaryCell(READ_LOCK);
1424 if (!tcell) /* no primary cell? */
1426 strcpy(aout, tcell->cellName);
1427 *aoutSize = strlen(aout) + 1;
1428 afs_PutCell(tcell, READ_LOCK);
1433 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1437 * \param[in] ain not in use (user id found via areq)
1438 * \param[out] aout cell name
1440 * \retval ESRCH Error if the user id doesn't have a primary cell specified
1442 * \post Get the primary cell for a certain user, based on the user's uid
1444 DECL_PIOCTL(PGetUserCell)
1446 register afs_int32 i;
1447 register struct unixuser *tu;
1448 register struct cell *tcell;
1450 AFS_STATCNT(PGetUserCell);
1451 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1452 return EIO; /* Inappropriate ioctl for device */
1454 /* return the cell name of the primary cell for this user */
1455 i = UHash(areq->uid);
1456 ObtainWriteLock(&afs_xuser, 224);
1457 for (tu = afs_users[i]; tu; tu = tu->next) {
1458 if (tu->uid == areq->uid && (tu->states & UPrimary)) {
1460 ReleaseWriteLock(&afs_xuser);
1465 tcell = afs_GetCell(tu->cell, READ_LOCK);
1466 afs_PutUser(tu, WRITE_LOCK);
1470 strcpy(aout, tcell->cellName);
1471 afs_PutCell(tcell, READ_LOCK);
1472 *aoutSize = strlen(aout) + 1; /* 1 for the null */
1475 ReleaseWriteLock(&afs_xuser);
1483 * VIOCSETTOK (3) - Set authentication tokens
1487 * \param[in] ain the krb tickets from which to set the afs tokens
1488 * \param[out] aout not in use
1490 * \retval EINVAL Error if the ticket is either too long or too short
1491 * \retval EIO Error if the AFS initState is below 101
1492 * \retval ESRCH Error if the cell for which the Token is being set can't be found
1494 * \post Set the Tokens for a specific cell name, unless there is none set, then default to primary
1497 DECL_PIOCTL(PSetTokens)
1500 register struct unixuser *tu;
1501 struct ClearToken clear;
1502 register struct cell *tcell;
1505 struct vrequest treq;
1506 afs_int32 flag, set_parent_pag = 0;
1508 AFS_STATCNT(PSetTokens);
1509 if (!afs_resourceinit_flag) {
1512 memcpy((char *)&i, ain, sizeof(afs_int32));
1513 ain += sizeof(afs_int32);
1514 stp = ain; /* remember where the ticket is */
1515 if (i < 0 || i > MAXKTCTICKETLEN)
1516 return EINVAL; /* malloc may fail */
1518 ain += i; /* skip over ticket */
1519 memcpy((char *)&i, ain, sizeof(afs_int32));
1520 ain += sizeof(afs_int32);
1521 if (i != sizeof(struct ClearToken)) {
1524 memcpy((char *)&clear, ain, sizeof(struct ClearToken));
1525 if (clear.AuthHandle == -1)
1526 clear.AuthHandle = 999; /* more rxvab compat stuff */
1527 ain += sizeof(struct ClearToken);
1528 if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) {
1529 /* still stuff left? we've got primary flag and cell name. Set these */
1530 memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */
1531 ain += sizeof(afs_int32); /* skip id field */
1532 /* rest is cell name, look it up */
1533 /* some versions of gcc appear to need != 0 in order to get this right */
1534 if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */
1538 tcell = afs_GetCellByName(ain, READ_LOCK);
1542 /* default to primary cell, primary id */
1543 flag = 1; /* primary id */
1544 tcell = afs_GetPrimaryCell(READ_LOCK);
1549 afs_PutCell(tcell, READ_LOCK);
1550 if (set_parent_pag) {
1552 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1553 #if defined(AFS_DARWIN_ENV)
1554 struct proc *p = current_proc(); /* XXX */
1556 struct proc *p = curproc; /* XXX */
1558 #ifndef AFS_DARWIN80_ENV
1559 uprintf("Process %d (%s) tried to change pags in PSetTokens\n",
1560 p->p_pid, p->p_comm);
1562 if (!setpag(p, acred, -1, &pag, 1)) {
1565 if (!setpag(u.u_procp, acred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
1567 if (!setpag(acred, -1, &pag, 1)) {
1570 afs_InitReq(&treq, *acred);
1574 /* now we just set the tokens */
1575 tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
1576 tu->vid = clear.ViceId;
1577 if (tu->stp != NULL) {
1578 afs_osi_Free(tu->stp, tu->stLen);
1580 tu->stp = (char *)afs_osi_Alloc(stLen);
1581 if (tu->stp == NULL) {
1585 memcpy(tu->stp, stp, stLen);
1588 afs_stats_cmfullperf.authent.TicketUpdates++;
1589 afs_ComputePAGStats();
1590 #endif /* AFS_NOSTATS */
1591 tu->states |= UHasTokens;
1592 tu->states &= ~UTokensBad;
1593 afs_SetPrimary(tu, flag);
1594 tu->tokenTime = osi_Time();
1595 afs_ResetUserConns(tu);
1596 afs_PutUser(tu, WRITE_LOCK);
1612 * VIOCGETVOLSTAT (4) - Get volume status
1616 * \param[in] ain not in use
1617 * \param[out] aout status of the volume
1619 * \retval EINVAL Error if some of the standard args aren't set
1621 * \post The status of a volume (based on the FID of the volume), or an offline message /motd
1623 DECL_PIOCTL(PGetVolumeStatus)
1626 char *offLineMsg = afs_osi_Alloc(256);
1627 char *motd = afs_osi_Alloc(256);
1628 register struct afs_conn *tc;
1629 register afs_int32 code = 0;
1630 struct AFSFetchVolumeStatus volstat;
1632 char *Name, *OfflineMsg, *MOTD;
1635 AFS_STATCNT(PGetVolumeStatus);
1641 OfflineMsg = offLineMsg;
1644 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1646 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
1649 RXAFS_GetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &volstat,
1650 &Name, &OfflineMsg, &MOTD);
1655 } while (afs_Analyze
1656 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
1657 SHARED_LOCK, NULL));
1661 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
1663 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1664 cp += sizeof(VolumeStatus);
1665 strcpy(cp, volName);
1666 cp += strlen(volName) + 1;
1667 strcpy(cp, offLineMsg);
1668 cp += strlen(offLineMsg) + 1;
1670 cp += strlen(motd) + 1;
1671 *aoutSize = (cp - aout);
1673 afs_osi_Free(offLineMsg, 256);
1674 afs_osi_Free(motd, 256);
1679 * VIOCSETVOLSTAT (5) - Set volume status
1683 * \param[in] ain values to set the status at, offline message, message of the day, volume name, minimum quota, maximum quota
1684 * \param[out] aout status of a volume, offlines messages, minimum quota, maximumm quota
1686 * \retval EINVAL Error if some of the standard args aren't set
1687 * \retval EROFS Error if the volume is read only, or a backup volume
1688 * \retval ENODEV Error if the volume can't be accessed
1689 * \retval E2BIG Error if the volume name, offline message, and motd are too big
1691 * \post Set the status of a volume, including any offline messages, a minimum quota, and a maximum quota
1693 DECL_PIOCTL(PSetVolumeStatus)
1696 char *offLineMsg = afs_osi_Alloc(256);
1697 char *motd = afs_osi_Alloc(256);
1698 register struct afs_conn *tc;
1699 register afs_int32 code = 0;
1700 struct AFSFetchVolumeStatus volstat;
1701 struct AFSStoreVolumeStatus storeStat;
1702 register struct volume *tvp;
1706 AFS_STATCNT(PSetVolumeStatus);
1712 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
1714 if (tvp->states & (VRO | VBackup)) {
1715 afs_PutVolume(tvp, READ_LOCK);
1719 afs_PutVolume(tvp, READ_LOCK);
1724 /* Copy the junk out, using cp as a roving pointer. */
1726 memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
1727 cp += sizeof(AFSFetchVolumeStatus);
1728 if (strlen(cp) >= sizeof(volName)) {
1732 strcpy(volName, cp);
1733 cp += strlen(volName) + 1;
1734 if (strlen(cp) >= sizeof(offLineMsg)) {
1738 strcpy(offLineMsg, cp);
1739 cp += strlen(offLineMsg) + 1;
1740 if (strlen(cp) >= sizeof(motd)) {
1746 if (volstat.MinQuota != -1) {
1747 storeStat.MinQuota = volstat.MinQuota;
1748 storeStat.Mask |= AFS_SETMINQUOTA;
1750 if (volstat.MaxQuota != -1) {
1751 storeStat.MaxQuota = volstat.MaxQuota;
1752 storeStat.Mask |= AFS_SETMAXQUOTA;
1755 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
1757 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
1760 RXAFS_SetVolumeStatus(tc->id, avc->f.fid.Fid.Volume, &storeStat,
1761 volName, offLineMsg, motd);
1766 } while (afs_Analyze
1767 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
1768 SHARED_LOCK, NULL));
1772 /* we are sending parms back to make compat. with prev system. should
1773 * change interface later to not ask for current status, just set new status */
1775 memcpy(cp, (char *)&volstat, sizeof(VolumeStatus));
1776 cp += sizeof(VolumeStatus);
1777 strcpy(cp, volName);
1778 cp += strlen(volName) + 1;
1779 strcpy(cp, offLineMsg);
1780 cp += strlen(offLineMsg) + 1;
1782 cp += strlen(motd) + 1;
1783 *aoutSize = cp - aout;
1785 afs_osi_Free(offLineMsg, 256);
1786 afs_osi_Free(motd, 256);
1791 * VIOCFLUSH (6) - Invalidate cache entry
1795 * \param[in] ain not in use
1796 * \param[out] aout not in use
1798 * \retval EINVAL Error if some of the standard args aren't set
1800 * \post Flush any information the cache manager has on an entry
1804 AFS_STATCNT(PFlush);
1807 #ifdef AFS_BOZONLOCK_ENV
1808 afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
1810 ObtainWriteLock(&avc->lock, 225);
1811 afs_ResetVCache(avc, *acred);
1812 ReleaseWriteLock(&avc->lock);
1813 #ifdef AFS_BOZONLOCK_ENV
1814 afs_BozonUnlock(&avc->pvnLock, avc);
1820 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
1824 * \param[in] ain the last component in a path, related to mountpoint that we're looking for information about
1825 * \param[out] aout volume, cell, link data
1827 * \retval EINVAL Error if some of the standard args aren't set
1828 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
1829 * \retval EIO Error if the link data can't be accessed
1831 * \post Get the volume, and cell, as well as the link data for a mount point
1833 DECL_PIOCTL(PNewStatMount)
1835 register afs_int32 code;
1836 register struct vcache *tvc;
1837 register struct dcache *tdc;
1838 struct VenusFid tfid;
1840 struct sysname_info sysState;
1841 afs_size_t offset, len;
1843 AFS_STATCNT(PNewStatMount);
1846 code = afs_VerifyVCache(avc, areq);
1849 if (vType(avc) != VDIR) {
1852 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
1855 Check_AtSys(avc, ain, &sysState, areq);
1856 ObtainReadLock(&tdc->lock);
1858 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
1859 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
1860 ReleaseReadLock(&tdc->lock);
1861 afs_PutDCache(tdc); /* we're done with the data */
1862 bufp = sysState.name;
1866 tfid.Cell = avc->f.fid.Cell;
1867 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
1868 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
1869 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
1871 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
1877 if (tvc->mvstat != 1) {
1882 ObtainWriteLock(&tvc->lock, 226);
1883 code = afs_HandleLink(tvc, areq);
1885 if (tvc->linkData) {
1886 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
1889 /* we have the data */
1890 strcpy(aout, tvc->linkData);
1891 *aoutSize = strlen(tvc->linkData) + 1;
1896 ReleaseWriteLock(&tvc->lock);
1899 if (sysState.allocked)
1900 osi_FreeLargeSpace(bufp);
1905 * VIOCGETTOK (8) - Get authentication tokens
1909 * \param[in] ain userid
1910 * \param[out] aout token
1912 * \retval EIO Error if the afs daemon hasn't started yet
1913 * \retval EDOM Error if the input parameter is out of the bounds of the available tokens
1914 * \retval ENOTCONN Error if there aren't tokens for this cell
1916 * \post If the input paramater exists, get the token that corresponds to the parameter value, if there is no token at this value, get the token for the first cell
1918 * \notes "it's a weird interface (from comments in the code)"
1921 DECL_PIOCTL(PGetTokens)
1923 register struct cell *tcell;
1924 register afs_int32 i;
1925 register struct unixuser *tu;
1930 AFS_STATCNT(PGetTokens);
1931 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
1932 return EIO; /* Inappropriate ioctl for device */
1934 /* weird interface. If input parameter is present, it is an integer and
1935 * we're supposed to return the parm'th tokens for this unix uid.
1936 * If not present, we just return tokens for cell 1.
1937 * If counter out of bounds, return EDOM.
1938 * If no tokens for the particular cell, return ENOTCONN.
1939 * Also, if this mysterious parm is present, we return, along with the
1940 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
1941 * at the end, in that order.
1943 if ((newStyle = (ainSize > 0))) {
1944 memcpy((char *)&iterator, ain, sizeof(afs_int32));
1946 i = UHash(areq->uid);
1947 ObtainReadLock(&afs_xuser);
1948 for (tu = afs_users[i]; tu; tu = tu->next) {
1950 if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
1951 if (iterator-- == 0)
1952 break; /* are we done yet? */
1955 if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
1961 * No need to hold a read lock on each user entry
1965 ReleaseReadLock(&afs_xuser);
1970 if (((tu->states & UHasTokens) == 0)
1971 || (tu->ct.EndTimestamp < osi_Time())) {
1972 tu->states |= (UTokensBad | UNeedsReset);
1973 afs_PutUser(tu, READ_LOCK);
1976 /* use iterator for temp */
1978 iterator = tu->stLen; /* for compat, we try to return 56 byte tix if they fit */
1980 iterator = 56; /* # of bytes we're returning */
1981 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1982 cp += sizeof(afs_int32);
1983 memcpy(cp, tu->stp, tu->stLen); /* copy out st */
1985 iterator = sizeof(struct ClearToken);
1986 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1987 cp += sizeof(afs_int32);
1988 memcpy(cp, (char *)&tu->ct, sizeof(struct ClearToken));
1989 cp += sizeof(struct ClearToken);
1991 /* put out primary id and cell name, too */
1992 iterator = (tu->states & UPrimary ? 1 : 0);
1993 memcpy(cp, (char *)&iterator, sizeof(afs_int32));
1994 cp += sizeof(afs_int32);
1995 tcell = afs_GetCell(tu->cell, READ_LOCK);
1997 strcpy(cp, tcell->cellName);
1998 cp += strlen(tcell->cellName) + 1;
1999 afs_PutCell(tcell, READ_LOCK);
2003 *aoutSize = cp - aout;
2004 afs_PutUser(tu, READ_LOCK);
2009 * VIOCUNLOG (9) - Invalidate tokens
2013 * \param[in] ain not in use
2014 * \param[out] aout not in use
2016 * \retval EIO Error if the afs daemon hasn't been started yet
2018 * \post remove tokens from a user, specified by the user id
2020 * \notes sets the token's time to 0, which then causes it to be removed
2021 * \notes Unlog is the same as un-pag in OpenAFS
2025 register afs_int32 i;
2026 register struct unixuser *tu;
2028 AFS_STATCNT(PUnlog);
2029 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2030 return EIO; /* Inappropriate ioctl for device */
2032 i = UHash(areq->uid);
2033 ObtainWriteLock(&afs_xuser, 227);
2034 for (tu = afs_users[i]; tu; tu = tu->next) {
2035 if (tu->uid == areq->uid) {
2037 tu->states &= ~UHasTokens;
2038 /* security is not having to say you're sorry */
2039 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
2041 ReleaseWriteLock(&afs_xuser);
2042 /* We have to drop the lock over the call to afs_ResetUserConns, since
2043 * it obtains the afs_xvcache lock. We could also keep the lock, and
2044 * modify ResetUserConns to take parm saying we obtained the lock
2045 * already, but that is overkill. By keeping the "tu" pointer
2046 * held over the released lock, we guarantee that we won't lose our
2047 * place, and that we'll pass over every user conn that existed when
2048 * we began this call.
2050 afs_ResetUserConns(tu);
2052 ObtainWriteLock(&afs_xuser, 228);
2054 /* set the expire times to 0, causes
2055 * afs_GCUserData to remove this entry
2057 tu->ct.EndTimestamp = 0;
2059 #endif /* UKERNEL */
2062 ReleaseWriteLock(&afs_xuser);
2067 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2071 * \param[in] ain host address to be set
2072 * \param[out] aout old host address
2074 * \post depending on whether or not a variable is set, either get the host for the cache manager monitor, or set the old address and give it a new address
2076 * \notes Errors turn off mariner
2078 DECL_PIOCTL(PMariner)
2080 afs_int32 newHostAddr;
2081 afs_int32 oldHostAddr;
2083 AFS_STATCNT(PMariner);
2085 memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
2088 oldHostAddr = 0xffffffff; /* disabled */
2090 memcpy((char *)&newHostAddr, ain, sizeof(afs_int32));
2091 if (newHostAddr == 0xffffffff) {
2092 /* disable mariner operations */
2094 } else if (newHostAddr) {
2096 afs_marinerHost = newHostAddr;
2098 memcpy(aout, (char *)&oldHostAddr, sizeof(afs_int32));
2099 *aoutSize = sizeof(afs_int32);
2104 * VIOCCKSERV (10) - Check that servers are up
2108 * \param[in] ain name of the cell
2109 * \param[out] aout current down server list
2111 * \retval EIO Error if the afs daemon hasn't started yet
2112 * \retval EACCES Error if the user doesn't have super-user credentials
2113 * \retval ENOENT Error if we are unable to obtain the cell
2115 * \post Either a fast check (where it doesn't contact servers) or a local check (checks local cell only)
2117 DECL_PIOCTL(PCheckServers)
2119 register char *cp = 0;
2121 register struct server *ts;
2122 afs_int32 temp, *lp = (afs_int32 *) ain, havecell = 0;
2124 struct chservinfo *pcheck;
2126 AFS_STATCNT(PCheckServers);
2128 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2129 return EIO; /* Inappropriate ioctl for device */
2131 if (*lp == 0x12345678) { /* For afs3.3 version */
2132 pcheck = (struct chservinfo *)ain;
2133 if (pcheck->tinterval >= 0) {
2135 memcpy(cp, (char *)&afs_probe_interval, sizeof(afs_int32));
2136 *aoutSize = sizeof(afs_int32);
2137 if (pcheck->tinterval > 0) {
2138 if (!afs_osi_suser(*acred))
2140 afs_probe_interval = pcheck->tinterval;
2146 temp = pcheck->tflags;
2147 cp = pcheck->tbuffer;
2148 } else { /* For pre afs3.3 versions */
2149 memcpy((char *)&temp, ain, sizeof(afs_int32));
2150 cp = ain + sizeof(afs_int32);
2151 if (ainSize > sizeof(afs_int32))
2156 * 1: fast check, don't contact servers.
2157 * 2: local cell only.
2160 /* have cell name, too */
2161 cellp = afs_GetCellByName(cp, READ_LOCK);
2166 if (!cellp && (temp & 2)) {
2167 /* use local cell */
2168 cellp = afs_GetPrimaryCell(READ_LOCK);
2170 if (!(temp & 1)) { /* if not fast, call server checker routine */
2171 afs_CheckServers(1, cellp); /* check down servers */
2172 afs_CheckServers(0, cellp); /* check up servers */
2174 /* now return the current down server list */
2176 ObtainReadLock(&afs_xserver);
2177 for (i = 0; i < NSERVERS; i++) {
2178 for (ts = afs_servers[i]; ts; ts = ts->next) {
2179 if (cellp && ts->cell != cellp)
2180 continue; /* cell spec'd and wrong */
2181 if ((ts->flags & SRVR_ISDOWN)
2182 && ts->addr->sa_portal != ts->cell->vlport) {
2183 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2184 cp += sizeof(afs_int32);
2188 ReleaseReadLock(&afs_xserver);
2190 afs_PutCell(cellp, READ_LOCK);
2191 *aoutSize = cp - aout;
2196 * VIOCCKBACK (11) - Check backup volume mappings
2200 * \param[in] ain not in use
2201 * \param[out] aout not in use
2203 * \retval EIO Error if the afs daemon hasn't started yet
2205 * \post Check the root volume, and then check the names if the volume check variable is set to force, has expired, is busy, or if the mount points variable is set
2207 DECL_PIOCTL(PCheckVolNames)
2209 AFS_STATCNT(PCheckVolNames);
2210 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2211 return EIO; /* Inappropriate ioctl for device */
2213 afs_CheckRootVolume();
2214 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
2215 AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
2220 * VIOCCKCONN (12) - Check connections for a user
2224 * \param[in] ain not in use
2225 * \param[out] aout not in use
2227 * \retval EACCESS Error if no user is specififed, the user has no tokens set, or if the user's tokens are bad
2229 * \post check to see if a user has the correct authentication. If so, allow access.
2231 * \notes Check the connections to all the servers specified
2233 DECL_PIOCTL(PCheckAuth)
2237 struct afs_conn *tc;
2238 struct unixuser *tu;
2241 AFS_STATCNT(PCheckAuth);
2242 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2243 return EIO; /* Inappropriate ioctl for device */
2246 tu = afs_GetUser(areq->uid, 1, READ_LOCK); /* check local cell authentication */
2250 /* we have a user */
2251 ObtainReadLock(&afs_xsrvAddr);
2252 ObtainReadLock(&afs_xconn);
2254 /* any tokens set? */
2255 if ((tu->states & UHasTokens) == 0)
2257 /* all connections in cell 1 working? */
2258 for (i = 0; i < NSERVERS; i++) {
2259 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
2260 for (tc = sa->conns; tc; tc = tc->next) {
2261 if (tc->user == tu && (tu->states & UTokensBad))
2266 ReleaseReadLock(&afs_xsrvAddr);
2267 ReleaseReadLock(&afs_xconn);
2268 afs_PutUser(tu, READ_LOCK);
2270 memcpy(aout, (char *)&retValue, sizeof(afs_int32));
2271 *aoutSize = sizeof(afs_int32);
2276 Prefetch(char *apath, struct afs_ioctl *adata, int afollow,
2277 struct AFS_UCRED *acred)
2280 register afs_int32 code;
2281 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2287 AFS_STATCNT(Prefetch);
2290 tp = osi_AllocLargeSpace(1024);
2291 AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
2293 osi_FreeLargeSpace(tp);
2296 if (afs_BBusy()) { /* do this as late as possible */
2297 osi_FreeLargeSpace(tp);
2298 return EWOULDBLOCK; /* pretty close */
2300 afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
2301 (afs_size_t) 0, tp);
2306 * VIOCWHEREIS (14) - Find out where a volume is located
2310 * \param[in] ain not in use
2311 * \param[out] aout volume location
2313 * \retval EINVAL Error if some of the default arguments don't exist
2314 * \retval ENODEV Error if there is no such volume
2316 * \post fine a volume, based on a volume file id
2318 * \notes check each of the servers specified
2320 DECL_PIOCTL(PFindVolume)
2322 register struct volume *tvp;
2323 register struct server *ts;
2324 register afs_int32 i;
2327 AFS_STATCNT(PFindVolume);
2330 tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
2333 for (i = 0; i < MAXHOSTS; i++) {
2334 ts = tvp->serverHost[i];
2337 memcpy(cp, (char *)&ts->addr->sa_ip, sizeof(afs_int32));
2338 cp += sizeof(afs_int32);
2341 /* still room for terminating NULL, add it on */
2342 ainSize = 0; /* reuse vbl */
2343 memcpy(cp, (char *)&ainSize, sizeof(afs_int32));
2344 cp += sizeof(afs_int32);
2346 *aoutSize = cp - aout;
2347 afs_PutVolume(tvp, READ_LOCK);
2354 * VIOCACCESS (20) - Access using PRS_FS bits
2358 * \param[in] ain PRS_FS bits
2359 * \param[out] aout not in use
2361 * \retval EINVAL Error if some of the initial arguments aren't set
2362 * \retval EACCES Error if access is denied
2364 * \post check to make sure access is allowed
2366 DECL_PIOCTL(PViceAccess)
2368 register afs_int32 code;
2371 AFS_STATCNT(PViceAccess);
2374 code = afs_VerifyVCache(avc, areq);
2377 memcpy((char *)&temp, ain, sizeof(afs_int32));
2378 code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
2385 DECL_PIOCTL(PPrecache)
2389 /*AFS_STATCNT(PPrecache);*/
2390 if (!afs_osi_suser(*acred))
2392 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2393 afs_preCache = newValue*1024;
2398 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2402 * \param[in] ain the size the venus cache should be set to
2403 * \param[out] aout not in use
2405 * \retval EACCES Error if the user doesn't have super-user credentials
2406 * \retval EROFS Error if the cache is set to be in memory
2408 * \post Set the cache size based on user input. If no size is given, set it to the default OpenAFS cache size.
2410 * \notes recompute the general cache parameters for every single block allocated
2412 DECL_PIOCTL(PSetCacheSize)
2417 AFS_STATCNT(PSetCacheSize);
2418 if (!afs_osi_suser(*acred))
2420 /* too many things are setup initially in mem cache version */
2421 if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
2423 memcpy((char *)&newValue, ain, sizeof(afs_int32));
2425 afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
2427 if (newValue < afs_min_cache)
2428 afs_cacheBlocks = afs_min_cache;
2430 afs_cacheBlocks = newValue;
2432 afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
2433 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2434 afs_MaybeWakeupTruncateDaemon();
2435 while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
2436 afs_osi_Wait(1000, 0, 0);
2437 afs_MaybeWakeupTruncateDaemon();
2442 #define MAXGCSTATS 16
2444 * VIOCGETCACHEPARMS (40) - Get cache stats
2448 * \param[in] ain afs index flags
2449 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2451 * \post Get the cache blocks, and how many of the cache blocks there are
2453 DECL_PIOCTL(PGetCacheSize)
2455 afs_int32 results[MAXGCSTATS];
2457 register struct dcache * tdc;
2460 AFS_STATCNT(PGetCacheSize);
2462 if (sizeof(afs_int32) == ainSize){
2463 memcpy((char *)&flags, ain, sizeof(afs_int32));
2464 } else if (0 == ainSize){
2470 memset((char *)results, 0, sizeof(results));
2471 results[0] = afs_cacheBlocks;
2472 results[1] = afs_blocksUsed;
2473 results[2] = afs_cacheFiles;
2476 for (i = 0; i < afs_cacheFiles; i++) {
2477 if (afs_indexFlags[i] & IFFree) results[3]++;
2479 } else if (2 == flags){
2480 for (i = 0; i < afs_cacheFiles; i++) {
2481 if (afs_indexFlags[i] & IFFree) results[3]++;
2482 if (afs_indexFlags[i] & IFEverUsed) results[4]++;
2483 if (afs_indexFlags[i] & IFDataMod) results[5]++;
2484 if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
2485 if (afs_indexFlags[i] & IFAnyPages) results[7]++;
2486 if (afs_indexFlags[i] & IFDiscarded) results[8]++;
2488 tdc = afs_indexTable[i];
2491 size = tdc->validPos;
2492 if ( 0 < size && size < (1<<12) ) results[10]++;
2493 else if (size < (1<<14) ) results[11]++;
2494 else if (size < (1<<16) ) results[12]++;
2495 else if (size < (1<<18) ) results[13]++;
2496 else if (size < (1<<20) ) results[14]++;
2497 else if (size >= (1<<20) ) results[15]++;
2501 memcpy(aout, (char *)results, sizeof(results));
2502 *aoutSize = sizeof(results);
2507 * VIOCFLUSHCB (25) - Flush callback only
2511 * \param[in] ain not in use
2512 * \param[out] aout not in use
2514 * \retval EINVAL Error if some of the standard args aren't set
2515 * \retval 0 0 returned if the volume is set to read-only
2517 * \post Flushes callbacks, by setting the length of callbacks to one, setting the next callback to be sent to the CB_DROPPED value, and then dequeues everything else.
2519 DECL_PIOCTL(PRemoveCallBack)
2521 register struct afs_conn *tc;
2522 register afs_int32 code = 0;
2523 struct AFSCallBack CallBacks_Array[1];
2524 struct AFSCBFids theFids;
2525 struct AFSCBs theCBs;
2528 AFS_STATCNT(PRemoveCallBack);
2531 if (avc->f.states & CRO)
2532 return 0; /* read-only-ness can't change */
2533 ObtainWriteLock(&avc->lock, 229);
2534 theFids.AFSCBFids_len = 1;
2535 theCBs.AFSCBs_len = 1;
2536 theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
2537 theCBs.AFSCBs_val = CallBacks_Array;
2538 CallBacks_Array[0].CallBackType = CB_DROPPED;
2539 if (avc->callback) {
2541 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2543 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
2545 code = RXAFS_GiveUpCallBacks(tc->id, &theFids, &theCBs);
2549 /* don't set code on failure since we wouldn't use it */
2550 } while (afs_Analyze
2551 (tc, code, &avc->f.fid, areq,
2552 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
2554 ObtainWriteLock(&afs_xcbhash, 457);
2555 afs_DequeueCallback(avc);
2557 avc->f.states &= ~(CStatd | CUnique);
2558 ReleaseWriteLock(&afs_xcbhash);
2559 if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
2560 osi_dnlc_purgedp(avc);
2562 ReleaseWriteLock(&avc->lock);
2567 * VIOCNEWCELL (26) - Configure new cell
2571 * \param[in] ain the name of the cell, the hosts that will be a part of the cell, whether or not it's linked with another cell, the other cell it's linked with, the file server port, and the volume server port
2572 * \param[out] aout not in use
2574 * \retval EIO Error if the afs daemon hasn't started yet
2575 * \retval EACCES Error if the user doesn't have super-user cedentials
2576 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
2578 * \post creates a new cell
2580 DECL_PIOCTL(PNewCell)
2582 /* create a new cell */
2583 afs_int32 cellHosts[MAXCELLHOSTS], *lp, magic = 0;
2584 char *newcell = 0, *linkedcell = 0, *tp = ain;
2585 register afs_int32 code, linkedstate = 0, ls;
2586 u_short fsport = 0, vlport = 0;
2589 AFS_STATCNT(PNewCell);
2590 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2591 return EIO; /* Inappropriate ioctl for device */
2593 if (!afs_osi_suser(*acred))
2596 memcpy((char *)&magic, tp, sizeof(afs_int32));
2597 tp += sizeof(afs_int32);
2598 if (magic != 0x12345678)
2601 /* A 3.4 fs newcell command will pass an array of MAXCELLHOSTS
2602 * server addresses while the 3.5 fs newcell command passes
2603 * MAXHOSTS. To figure out which is which, check if the cellname
2606 newcell = tp + (MAXCELLHOSTS + 3) * sizeof(afs_int32);
2607 scount = ((newcell[0] != '\0') ? MAXCELLHOSTS : MAXHOSTS);
2609 /* MAXCELLHOSTS (=8) is less than MAXHOSTS (=13) */
2610 memcpy((char *)cellHosts, tp, MAXCELLHOSTS * sizeof(afs_int32));
2611 tp += (scount * sizeof(afs_int32));
2613 lp = (afs_int32 *) tp;
2617 fsport = 0; /* Privileged ports not allowed */
2619 vlport = 0; /* Privileged ports not allowed */
2620 tp += (3 * sizeof(afs_int32));
2622 if ((ls = *lp) & 1) {
2623 linkedcell = tp + strlen(newcell) + 1;
2624 linkedstate |= CLinkedCell;
2627 linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
2629 afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
2634 DECL_PIOCTL(PNewAlias)
2636 /* create a new cell alias */
2638 register afs_int32 code;
2639 char *realName, *aliasName;
2641 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2642 return EIO; /* Inappropriate ioctl for device */
2644 if (!afs_osi_suser(*acred))
2648 tp += strlen(aliasName) + 1;
2651 code = afs_NewCellAlias(aliasName, realName);
2657 * VIOCGETCELL (27) - Get cell info
2661 * \param[in] ain The cell index of a specific cell
2662 * \param[out] aout list of servers in the cell
2664 * \retval EIO Error if the afs daemon hasn't started yet
2665 * \retval EDOM Error if there is no cell asked about
2667 * \post Lists the cell's server names and and addresses
2669 DECL_PIOCTL(PListCells)
2671 afs_int32 whichCell;
2672 register struct cell *tcell = 0;
2673 register afs_int32 i;
2674 register char *cp, *tp = ain;
2676 AFS_STATCNT(PListCells);
2677 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2678 return EIO; /* Inappropriate ioctl for device */
2680 memcpy((char *)&whichCell, tp, sizeof(afs_int32));
2681 tp += sizeof(afs_int32);
2682 tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
2685 memset(cp, 0, MAXCELLHOSTS * sizeof(afs_int32));
2686 for (i = 0; i < MAXCELLHOSTS; i++) {
2687 if (tcell->cellHosts[i] == 0)
2689 memcpy(cp, (char *)&tcell->cellHosts[i]->addr->sa_ip,
2691 cp += sizeof(afs_int32);
2693 cp = aout + MAXCELLHOSTS * sizeof(afs_int32);
2694 strcpy(cp, tcell->cellName);
2695 cp += strlen(tcell->cellName) + 1;
2696 *aoutSize = cp - aout;
2697 afs_PutCell(tcell, READ_LOCK);
2705 DECL_PIOCTL(PListAliases)
2707 afs_int32 whichAlias;
2708 register struct cell_alias *tcalias = 0;
2709 register char *cp, *tp = ain;
2711 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2712 return EIO; /* Inappropriate ioctl for device */
2713 if (ainSize < sizeof(afs_int32))
2716 memcpy((char *)&whichAlias, tp, sizeof(afs_int32));
2717 tp += sizeof(afs_int32);
2719 tcalias = afs_GetCellAlias(whichAlias);
2722 strcpy(cp, tcalias->alias);
2723 cp += strlen(tcalias->alias) + 1;
2724 strcpy(cp, tcalias->cell);
2725 cp += strlen(tcalias->cell) + 1;
2726 *aoutSize = cp - aout;
2727 afs_PutCellAlias(tcalias);
2736 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
2740 * \param[in] ain the name of the file in this dir to remove
2741 * \param[out] aout not in use
2743 * \retval EINVAL Error if some of the standard args aren't set
2744 * \retval ENOTDIR Error if the argument to remove is not a directory
2745 * \retval ENOENT Error if there is no cache to remove the mount point from or if a vcache doesn't exist
2747 * \post Ensure that everything is OK before deleting the mountpoint. If not, don't delete. Delete a mount point based on a file id.
2749 DECL_PIOCTL(PRemoveMount)
2751 register afs_int32 code;
2753 struct sysname_info sysState;
2754 afs_size_t offset, len;
2755 register struct afs_conn *tc;
2756 register struct dcache *tdc;
2757 register struct vcache *tvc;
2758 struct AFSFetchStatus OutDirStatus;
2759 struct VenusFid tfid;
2760 struct AFSVolSync tsync;
2764 /* "ain" is the name of the file in this dir to remove */
2766 AFS_STATCNT(PRemoveMount);
2769 code = afs_VerifyVCache(avc, areq);
2772 if (vType(avc) != VDIR)
2775 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1); /* test for error below */
2778 Check_AtSys(avc, ain, &sysState, areq);
2779 ObtainReadLock(&tdc->lock);
2781 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
2782 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
2783 ReleaseReadLock(&tdc->lock);
2784 bufp = sysState.name;
2789 tfid.Cell = avc->f.fid.Cell;
2790 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
2791 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
2792 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
2794 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
2801 if (tvc->mvstat != 1) {
2807 ObtainWriteLock(&tvc->lock, 230);
2808 code = afs_HandleLink(tvc, areq);
2810 if (tvc->linkData) {
2811 if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
2816 ReleaseWriteLock(&tvc->lock);
2817 osi_dnlc_purgedp(tvc);
2823 ObtainWriteLock(&avc->lock, 231);
2824 osi_dnlc_remove(avc, bufp, tvc);
2826 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
2828 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
2831 RXAFS_RemoveFile(tc->id, (struct AFSFid *)&avc->f.fid.Fid, bufp,
2832 &OutDirStatus, &tsync);
2837 } while (afs_Analyze
2838 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
2839 SHARED_LOCK, NULL));
2844 ReleaseWriteLock(&avc->lock);
2848 /* we have the thing in the cache */
2849 ObtainWriteLock(&tdc->lock, 661);
2850 if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
2851 /* we can do it locally */
2852 code = afs_dir_Delete(tdc, bufp);
2854 ZapDCE(tdc); /* surprise error -- invalid value */
2858 ReleaseWriteLock(&tdc->lock);
2859 afs_PutDCache(tdc); /* drop ref count */
2861 avc->f.states &= ~CUnique; /* For the dfs xlator */
2862 ReleaseWriteLock(&avc->lock);
2865 if (sysState.allocked)
2866 osi_FreeLargeSpace(bufp);
2871 * VIOC_VENUSLOG (34) - Enable/Disable venus logging
2875 * \retval EINVAL Error if some of the standard args aren't set
2877 * \notes Obsoleted, perhaps should be PBogus
2879 DECL_PIOCTL(PVenusLogging)
2881 return EINVAL; /* OBSOLETE */
2885 * VIOC_GETCELLSTATUS (35) - Get cell status info
2889 * \param[in] ain The cell you want status information on
2890 * \param[out] aout cell state (as a struct)
2892 * \retval EIO Error if the afs daemon hasn't started yet
2893 * \retval ENOENT Error if the cell doesn't exist
2895 * \post Returns the state of the cell as defined in a struct cell
2897 DECL_PIOCTL(PGetCellStatus)
2899 register struct cell *tcell;
2902 AFS_STATCNT(PGetCellStatus);
2903 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2904 return EIO; /* Inappropriate ioctl for device */
2906 tcell = afs_GetCellByName(ain, READ_LOCK);
2909 temp = tcell->states;
2910 afs_PutCell(tcell, READ_LOCK);
2911 memcpy(aout, (char *)&temp, sizeof(afs_int32));
2912 *aoutSize = sizeof(afs_int32);
2917 * VIOC_SETCELLSTATUS (36) - Set corresponding info
2921 * \param[in] ain The cell you want to set information about, and the values you want to set
2922 * \param[out] aout not in use
2924 * \retval EIO Error if the afs daemon hasn't started yet
2925 * \retval EACCES Error if the user doesn't have super-user credentials
2927 * \post Set the state of the cell in a defined struct cell, based on whether or not SetUID is allowed
2929 DECL_PIOCTL(PSetCellStatus)
2931 register struct cell *tcell;
2934 if (!afs_osi_suser(*acred))
2936 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2937 return EIO; /* Inappropriate ioctl for device */
2939 tcell = afs_GetCellByName(ain + 2 * sizeof(afs_int32), WRITE_LOCK);
2942 memcpy((char *)&temp, ain, sizeof(afs_int32));
2944 tcell->states |= CNoSUID;
2946 tcell->states &= ~CNoSUID;
2947 afs_PutCell(tcell, WRITE_LOCK);
2952 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
2956 * \param[in] ain not in use (args in avc)
2957 * \param[out] aout not in use
2959 * \retval EINVAL Error if some of the standard args aren't set
2960 * \retval EIO Error if the afs daemon hasn't started yet
2962 * \post Wipe everything on the volume. This is done dependent on which platform this is for.
2964 * \notes Does not flush a file that a user has open and is using, because it will be re-created on next write. Also purges the dnlc, because things are screwed up.
2966 DECL_PIOCTL(PFlushVolumeData)
2968 register afs_int32 i;
2969 register struct dcache *tdc;
2970 register struct vcache *tvc;
2971 register struct volume *tv;
2972 afs_int32 cell, volume;
2973 struct afs_q *tq, *uq;
2974 #ifdef AFS_DARWIN80_ENV
2978 AFS_STATCNT(PFlushVolumeData);
2981 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
2982 return EIO; /* Inappropriate ioctl for device */
2984 volume = avc->f.fid.Fid.Volume; /* who to zap */
2985 cell = avc->f.fid.Cell;
2988 * Clear stat'd flag from all vnodes from this volume; this will invalidate all
2989 * the vcaches associated with the volume.
2992 ObtainReadLock(&afs_xvcache);
2993 i = VCHashV(&avc->f.fid);
2994 for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
2997 if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
2998 if (tvc->f.states & CVInit) {
2999 ReleaseReadLock(&afs_xvcache);
3000 afs_osi_Sleep(&tvc->f.states);
3003 #ifdef AFS_DARWIN80_ENV
3004 if (tvc->f.states & CDeadVnode) {
3005 ReleaseReadLock(&afs_xvcache);
3006 afs_osi_Sleep(&tvc->f.states);
3010 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_LINUX20_ENV)
3011 VN_HOLD(AFSTOV(tvc));
3013 #ifdef AFS_DARWIN80_ENV
3017 if (vnode_ref(vp)) {
3024 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
3027 VREFCOUNT_INC(tvc); /* AIX, apparently */
3031 ReleaseReadLock(&afs_xvcache);
3032 #ifdef AFS_BOZONLOCK_ENV
3033 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
3035 ObtainWriteLock(&tvc->lock, 232);
3037 ObtainWriteLock(&afs_xcbhash, 458);
3038 afs_DequeueCallback(tvc);
3039 tvc->f.states &= ~(CStatd | CDirty);
3040 ReleaseWriteLock(&afs_xcbhash);
3041 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
3042 osi_dnlc_purgedp(tvc);
3043 afs_TryToSmush(tvc, *acred, 1);
3044 ReleaseWriteLock(&tvc->lock);
3045 #ifdef AFS_BOZONLOCK_ENV
3046 afs_BozonUnlock(&tvc->pvnLock, tvc);
3048 #ifdef AFS_DARWIN80_ENV
3049 vnode_put(AFSTOV(tvc));
3051 ObtainReadLock(&afs_xvcache);
3053 /* our tvc ptr is still good until now */
3057 ReleaseReadLock(&afs_xvcache);
3060 MObtainWriteLock(&afs_xdcache, 328); /* needed if you're going to flush any stuff */
3061 for (i = 0; i < afs_cacheFiles; i++) {
3062 if (!(afs_indexFlags[i] & IFEverUsed))
3063 continue; /* never had any data */
3064 tdc = afs_GetDSlot(i, NULL);
3065 if (tdc->refCount <= 1) { /* too high, in use by running sys call */
3066 ReleaseReadLock(&tdc->tlock);
3067 if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
3068 if (!(afs_indexFlags[i] & IFDataMod)) {
3069 /* if the file is modified, but has a ref cnt of only 1, then
3070 * someone probably has the file open and is writing into it.
3071 * Better to skip flushing such a file, it will be brought back
3072 * immediately on the next write anyway.
3074 * If we *must* flush, then this code has to be rearranged to call
3075 * afs_storeAllSegments() first */
3076 afs_FlushDCache(tdc);
3080 ReleaseReadLock(&tdc->tlock);
3082 afs_PutDCache(tdc); /* bumped by getdslot */
3084 MReleaseWriteLock(&afs_xdcache);
3086 ObtainReadLock(&afs_xvolume);
3087 for (i = 0; i < NVOLS; i++) {
3088 for (tv = afs_volumes[i]; tv; tv = tv->next) {
3089 if (tv->volume == volume) {
3090 afs_ResetVolumeInfo(tv);
3095 ReleaseReadLock(&afs_xvolume);
3097 /* probably, a user is doing this, probably, because things are screwed up.
3098 * maybe it's the dnlc's fault? */
3105 * VIOCGETVCXSTATUS (41) - gets vnode x status
3109 * \param[in] ain not in use (avc used)
3110 * \param[out] aout vcxstat: the file id, the data version, any lock, the parent vnode, the parent unique id, the trunc position, the callback, cbExpires, what access is being made, what files are open, any users executing/writing, the flock ount, the states, the move stat
3112 * \retval EINVAL Error if some of the initial default arguments aren't set
3113 * \retval EACCES Error if access to check the mode bits is denied
3115 * \post gets stats for the vnode, a struct listed in vcxstat
3117 DECL_PIOCTL(PGetVnodeXStatus)
3119 register afs_int32 code;
3120 struct vcxstat stat;
3123 /* AFS_STATCNT(PGetVnodeXStatus); */
3126 code = afs_VerifyVCache(avc, areq);
3129 if (vType(avc) == VDIR)
3130 mode = PRSFS_LOOKUP;
3133 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3136 memset(&stat, 0, sizeof(struct vcxstat));
3137 stat.fid = avc->f.fid;
3138 hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
3139 stat.lock = avc->lock;
3140 stat.parentVnode = avc->f.parent.vnode;
3141 stat.parentUnique = avc->f.parent.unique;
3142 hset(stat.flushDV, avc->flushDV);
3143 hset(stat.mapDV, avc->mapDV);
3144 stat.truncPos = avc->f.truncPos;
3145 { /* just grab the first two - won't break anything... */
3146 struct axscache *ac;
3148 for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
3149 stat.randomUid[i] = ac->uid;
3150 stat.randomAccess[i] = ac->axess;
3153 stat.callback = afs_data_pointer_to_int32(avc->callback);
3154 stat.cbExpires = avc->cbExpires;
3155 stat.anyAccess = avc->f.anyAccess;
3156 stat.opens = avc->opens;
3157 stat.execsOrWriters = avc->execsOrWriters;
3158 stat.flockCount = avc->flockCount;
3159 stat.mvstat = avc->mvstat;
3160 stat.states = avc->f.states;
3161 memcpy(aout, (char *)&stat, sizeof(struct vcxstat));
3162 *aoutSize = sizeof(struct vcxstat);
3167 DECL_PIOCTL(PGetVnodeXStatus2)
3169 register afs_int32 code;
3170 struct vcxstat2 stat;
3175 code = afs_VerifyVCache(avc, areq);
3178 if (vType(avc) == VDIR)
3179 mode = PRSFS_LOOKUP;
3182 if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
3185 memset(&stat, 0, sizeof(struct vcxstat2));
3187 stat.cbExpires = avc->cbExpires;
3188 stat.anyAccess = avc->f.anyAccess;
3189 stat.mvstat = avc->mvstat;
3190 stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
3192 memcpy(aout, (char *)&stat, sizeof(struct vcxstat2));
3193 *aoutSize = sizeof(struct vcxstat2);
3199 * VIOC_AFS_SYSNAME (38) - Change @sys value
3203 * \param[in] ain new value for @sys
3204 * \param[out] aout count, entry, list (debug values?)
3206 * \retval EINVAL Error if afsd isn't running, the new sysname is too large, the new sysname causes issues (starts with a .0 or ..0), there is no PAG set in the credentials, the user of a PAG can't be found, (!(exporter = au->exporter)) "NOT SURE ON THIS"
3207 * \retval ENODEV Error if there isn't already a system named that ("I THINK")
3208 * \retval EACCES Error if the user doesn't have super-user credentials
3210 * \post Set the value of @sys if these things work: if the input isn't too long or if input doesn't start with .0 or ..0
3212 * \notes We require root for local sysname changes, but not for remote (since we don't really believe remote uids anyway) outname[] shouldn't really be needed- this is left as an exercise for the reader.
3214 DECL_PIOCTL(PSetSysName)
3216 char *cp, *cp2 = NULL, inname[MAXSYSNAME], outname[MAXSYSNAME];
3217 afs_int32 setsysname;
3219 register struct afs_exporter *exporter;
3220 register struct unixuser *au;
3221 register afs_int32 pag, error;
3222 int t, count, num = 0, allpags = 0;
3225 AFS_STATCNT(PSetSysName);
3226 if (!afs_globalVFS) {
3227 /* Afsd is NOT running; disable it */
3228 #if defined(KERNEL_HAVE_UERROR)
3229 return (setuerror(EINVAL), EINVAL);
3234 memset(inname, 0, MAXSYSNAME);
3235 memcpy(&setsysname, ain, sizeof(afs_int32));
3236 ain += sizeof(afs_int32);
3237 if (setsysname & 0x8000) {
3239 setsysname &= ~0x8000;
3244 if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
3247 for (cp = ain, count = 0; count < setsysname; count++) {
3248 /* won't go past end of ain since maxsysname*num < ain length */
3250 if (t >= MAXSYSNAME || t <= 0)
3252 /* check for names that can shoot us in the foot */
3253 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
3259 /* inname gets first entry in case we're being a translator */
3261 memcpy(inname, ain, t + 1); /* include terminating null */
3265 if ((*acred)->cr_gid == RMTUSER_REQ ||
3266 (*acred)->cr_gid == RMTUSER_REQ_PRIV) { /* Handles all exporters */
3267 if (allpags && (*acred)->cr_gid != RMTUSER_REQ_PRIV) {
3270 pag = PagInCred(*acred);
3272 return EINVAL; /* Better than panicing */
3274 if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
3275 return EINVAL; /* Better than panicing */
3277 if (!(exporter = au->exporter)) {
3278 afs_PutUser(au, READ_LOCK);
3279 return EINVAL; /* Better than panicing */
3281 error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), &sysnamelist,
3284 if (error == ENODEV)
3285 foundname = 0; /* sysname not set yet! */
3287 afs_PutUser(au, READ_LOCK);
3292 strcpy(outname, sysnamelist[0]);
3294 afs_PutUser(au, READ_LOCK);
3298 /* Not xlating, so local case */
3300 osi_Panic("PSetSysName: !afs_sysname\n");
3301 if (!setsysname) { /* user just wants the info */
3302 strcpy(outname, afs_sysname);
3303 foundname = afs_sysnamecount;
3304 sysnamelist = afs_sysnamelist;
3305 } else { /* Local guy; only root can change sysname */
3306 if (!afs_osi_suser(*acred))
3309 /* allpags makes no sense for local use */
3313 /* clear @sys entries from the dnlc, once afs_lookup can
3314 * do lookups of @sys entries and thinks it can trust them */
3315 /* privs ok, store the entry, ... */
3316 strcpy(afs_sysname, inname);
3317 if (setsysname > 1) { /* ... or list */
3319 for (count = 1; count < setsysname; ++count) {
3320 if (!afs_sysnamelist[count])
3322 ("PSetSysName: no afs_sysnamelist entry to write\n");
3324 memcpy(afs_sysnamelist[count], cp, t + 1); /* include null */
3328 afs_sysnamecount = setsysname;
3333 cp = aout; /* not changing so report back the count and ... */
3334 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
3335 cp += sizeof(afs_int32);
3337 strcpy(cp, outname); /* ... the entry, ... */
3338 cp += strlen(outname) + 1;
3339 for (count = 1; count < foundname; ++count) { /* ... or list. */
3340 if (!sysnamelist[count])
3342 ("PSetSysName: no afs_sysnamelist entry to read\n");
3343 t = strlen(sysnamelist[count]);
3344 if (t >= MAXSYSNAME)
3345 osi_Panic("PSetSysName: sysname entry garbled\n");
3346 strcpy(cp, sysnamelist[count]);
3350 *aoutSize = cp - aout;
3355 /* sequential search through the list of touched cells is not a good
3356 * long-term solution here. For small n, though, it should be just
3357 * fine. Should consider special-casing the local cell for large n.
3358 * Likewise for PSetSPrefs.
3360 * s - number of ids in array l[] -- NOT index of last id
3361 * l - array of cell ids which have volumes that need to be sorted
3362 * vlonly - sort vl servers or file servers?
3365 ReSortCells_cb(struct cell *cell, void *arg)
3367 afs_int32 *p = (afs_int32 *) arg;
3368 afs_int32 *l = p + 1;
3371 for (i = 0; i < s; i++) {
3372 if (l[i] == cell->cellNum) {
3373 ObtainWriteLock(&cell->lock, 690);
3374 afs_SortServers(cell->cellHosts, MAXCELLHOSTS);
3375 ReleaseWriteLock(&cell->lock);
3383 ReSortCells(int s, afs_int32 * l, int vlonly)
3391 p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
3393 memcpy(p + 1, l, s * sizeof(afs_int32));
3394 afs_TraverseCells(&ReSortCells_cb, p);
3395 afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
3399 ObtainReadLock(&afs_xvolume);
3400 for (i = 0; i < NVOLS; i++) {
3401 for (j = afs_volumes[i]; j; j = j->next) {
3402 for (k = 0; k < s; k++)
3403 if (j->cell == l[k]) {
3404 ObtainWriteLock(&j->lock, 233);
3405 afs_SortServers(j->serverHost, MAXHOSTS);
3406 ReleaseWriteLock(&j->lock);
3411 ReleaseReadLock(&afs_xvolume);
3415 static int debugsetsp = 0;
3417 afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
3420 int i, j, k, matches, touchedSize;
3421 struct server *srvr = NULL;
3422 afs_int32 touched[34];
3426 for (k = 0; k < num; sp++, k++) {
3428 printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
3431 ObtainReadLock(&afs_xserver);
3433 i = SHash(sp->host.s_addr);
3434 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
3435 if (sa->sa_ip == sp->host.s_addr) {
3437 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3438 || (sa->sa_portal == AFS_FSPORT);
3439 if ((!vlonly && isfs) || (vlonly && !isfs)) {
3446 if (sa && matches) { /* found one! */
3448 printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
3450 sa->sa_iprank = sp->rank + afs_randomMod15();
3451 afs_SortOneServer(sa->server);
3454 /* if we don't know yet what cell it's in, this is moot */
3455 for (j = touchedSize - 1;
3456 j >= 0 && touched[j] != srvr->cell->cellNum; j--)
3457 /* is it in our list of touched cells ? */ ;
3458 if (j < 0) { /* no, it's not */
3459 touched[touchedSize++] = srvr->cell->cellNum;
3460 if (touchedSize >= 32) { /* watch for ovrflow */
3461 ReleaseReadLock(&afs_xserver);
3462 ReSortCells(touchedSize, touched, vlonly);
3464 ObtainReadLock(&afs_xserver);
3470 ReleaseReadLock(&afs_xserver);
3471 /* if we didn't find one, start to create one. */
3472 /* Note that it doesn't have a cell yet... */
3474 afs_uint32 temp = sp->host.s_addr;
3476 afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
3477 WRITE_LOCK, (afsUUID *) 0, 0);
3478 srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
3479 afs_PutServer(srvr, WRITE_LOCK);
3481 } /* for all cited preferences */
3483 ReSortCells(touchedSize, touched, vlonly);
3488 * VIOC_SETPREFS (46) - Set server ranks
3490 * \param[in] ain the sprefs value you want the sprefs to be set to
3491 * \param[out] aout not in use
3493 * \retval EIO Error if the afs daemon hasn't started yet
3494 * \retval EACCES Error if the user doesn't have super-user credentials
3495 * \retval EINVAL Error if the struct setsprefs is too large or if it multiplied by the number of servers is too large
3497 * \post set the sprefs using the afs_setsprefs() function
3499 DECL_PIOCTL(PSetSPrefs)
3501 struct setspref *ssp;
3502 AFS_STATCNT(PSetSPrefs);
3504 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3505 return EIO; /* Inappropriate ioctl for device */
3507 if (!afs_osi_suser(*acred))
3510 if (ainSize < sizeof(struct setspref))
3513 ssp = (struct setspref *)ain;
3514 if (ainSize < sizeof(struct spref) * ssp->num_servers)
3517 afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
3518 (ssp->flags & DBservers));
3523 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
3525 * \param[in] ain the server preferences to be set
3526 * \param[out] aout not in use
3528 * \retval EIO Error if the afs daemon hasn't started yet
3529 * \retval EACCES Error if the user doesn't have super-user credentials
3531 * \post set the server preferences, calling a function
3533 * \notes this may only be performed by the local root user.
3535 DECL_PIOCTL(PSetSPrefs33)
3538 AFS_STATCNT(PSetSPrefs);
3539 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3540 return EIO; /* Inappropriate ioctl for device */
3543 if (!afs_osi_suser(*acred))
3546 sp = (struct spref *)ain;
3547 afs_setsprefs(sp, ainSize / (sizeof(struct spref)), 0 /*!vlonly */ );
3552 * VIOC_GETSPREFS (43) - Get server ranks
3556 * \param[in] ain the server preferences to get
3557 * \param[out] aout the server preferences information
3559 * \retval EIO Error if the afs daemon hasn't started yet
3560 * \retval ENOENT Error if the sprefrequest is too large
3562 * \post Get the sprefs
3564 * \notes in the hash table of server structs, all servers with the same IP address; will be on the same overflow chain; This could be sped slightly in some circumstances by having it cache the immediately previous slot in the hash table and some supporting information; Only reports file servers now.
3566 DECL_PIOCTL(PGetSPrefs)
3568 struct sprefrequest *spin; /* input */
3569 struct sprefinfo *spout; /* output */
3570 struct spref *srvout; /* one output component */
3571 int i, j; /* counters for hash table traversal */
3572 struct server *srvr; /* one of CM's server structs */
3574 int vlonly; /* just return vlservers ? */
3577 AFS_STATCNT(PGetSPrefs);
3578 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
3579 return EIO; /* Inappropriate ioctl for device */
3582 if (ainSize < sizeof(struct sprefrequest_33)) {
3585 spin = ((struct sprefrequest *)ain);
3588 if (ainSize > sizeof(struct sprefrequest_33)) {
3589 vlonly = (spin->flags & DBservers);
3593 /* struct sprefinfo includes 1 server struct... that size gets added
3594 * in during the loop that follows.
3596 *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref);
3597 spout = (struct sprefinfo *)aout;
3598 spout->next_offset = spin->offset;
3599 spout->num_servers = 0;
3600 srvout = spout->servers;
3602 ObtainReadLock(&afs_xserver);
3603 for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */
3604 for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
3605 if (spin->offset > (unsigned short)i) {
3606 continue; /* catch up to where we left off */
3608 spout->next_offset++;
3611 isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
3612 || (sa->sa_portal == AFS_FSPORT);
3614 if ((vlonly && isfs) || (!vlonly && !isfs)) {
3615 /* only report ranks for vl servers */
3619 srvout->host.s_addr = sa->sa_ip;
3620 srvout->rank = sa->sa_iprank;
3621 *aoutSize += sizeof(struct spref);
3622 spout->num_servers++;
3625 if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) {
3626 ReleaseReadLock(&afs_xserver); /* no more room! */
3631 ReleaseReadLock(&afs_xserver);
3633 spout->next_offset = 0; /* start over from the beginning next time */
3637 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
3638 int afs_NFSRootOnly = 1;
3640 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
3644 * \param[in] ain a struct Vic * EIOctl containing export values needed to change between nfs and afs
3645 * \param[out] aout a struct of the exporter states (exporter->exp_states)
3647 * \retval ENODEV Error if the exporter doesn't exist
3648 * \retval EACCES Error if the user doesn't have super-user credentials
3650 * \post Changes the state of various values to reflect the change of the export values between nfs and afs.
3652 * \notes Legacy code obtained from IBM.
3654 DECL_PIOCTL(PExportAfs)
3656 afs_int32 export, newint =
3657 0, type, changestate, handleValue, convmode, pwsync, smounts;
3658 afs_int32 rempags = 0, pagcb = 0;
3659 register struct afs_exporter *exporter;
3661 AFS_STATCNT(PExportAfs);
3662 memcpy((char *)&handleValue, ain, sizeof(afs_int32));
3663 type = handleValue >> 24;
3668 exporter = exporter_find(type);
3670 export = handleValue & 3;
3671 changestate = handleValue & 0xfff;
3672 smounts = (handleValue >> 2) & 3;
3673 pwsync = (handleValue >> 4) & 3;
3674 convmode = (handleValue >> 6) & 3;
3675 rempags = (handleValue >> 8) & 3;
3676 pagcb = (handleValue >> 10) & 3;
3678 changestate = (handleValue >> 16) & 0x1;
3679 convmode = (handleValue >> 16) & 0x2;
3680 pwsync = (handleValue >> 16) & 0x4;
3681 smounts = (handleValue >> 16) & 0x8;
3682 export = handleValue & 0xff;
3685 /* Failed finding desired exporter; */
3689 handleValue = exporter->exp_states;
3690 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3691 *aoutSize = sizeof(afs_int32);
3693 if (!afs_osi_suser(*acred))
3694 return EACCES; /* Only superuser can do this */
3698 exporter->exp_states |= EXP_EXPORTED;
3700 exporter->exp_states &= ~EXP_EXPORTED;
3704 exporter->exp_states |= EXP_UNIXMODE;
3706 exporter->exp_states &= ~EXP_UNIXMODE;
3710 exporter->exp_states |= EXP_PWSYNC;
3712 exporter->exp_states &= ~EXP_PWSYNC;
3716 afs_NFSRootOnly = 0;
3717 exporter->exp_states |= EXP_SUBMOUNTS;
3719 afs_NFSRootOnly = 1;
3720 exporter->exp_states &= ~EXP_SUBMOUNTS;
3725 exporter->exp_states |= EXP_CLIPAGS;
3727 exporter->exp_states &= ~EXP_CLIPAGS;
3731 exporter->exp_states |= EXP_CALLBACK;
3733 exporter->exp_states &= ~EXP_CALLBACK;
3735 handleValue = exporter->exp_states;
3736 memcpy(aout, (char *)&handleValue, sizeof(afs_int32));
3737 *aoutSize = sizeof(afs_int32);
3740 exporter->exp_states |= EXP_EXPORTED;
3742 exporter->exp_states &= ~EXP_EXPORTED;
3744 exporter->exp_states |= EXP_UNIXMODE;
3746 exporter->exp_states &= ~EXP_UNIXMODE;
3748 exporter->exp_states |= EXP_PWSYNC;
3750 exporter->exp_states &= ~EXP_PWSYNC;
3752 afs_NFSRootOnly = 0;
3753 exporter->exp_states |= EXP_SUBMOUNTS;
3755 afs_NFSRootOnly = 1;
3756 exporter->exp_states &= ~EXP_SUBMOUNTS;
3765 * VIOC_GAG (44) - Silence Cache Manager
3769 * \param[in] ain the flags to either gag or de-gag the cache manager
3770 * \param[out] aout not in use
3772 * \retval EACCES Error if the user doesn't have super-user credentials
3774 * \post set the gag flags, then show these flags
3778 struct gaginfo *gagflags;
3780 if (!afs_osi_suser(*acred))
3783 gagflags = (struct gaginfo *)ain;
3784 afs_showflags = gagflags->showflags;
3790 * VIOC_TWIDDLE (45) - Adjust RX knobs
3794 * \param[in] ain the previous settings of the 'knobs'
3795 * \param[out] aout not in use
3797 * \retval EACCES Error if the user doesn't have super-user credentials
3799 * \post build out the struct rxp, from a struct rx
3801 DECL_PIOCTL(PTwiddleRx)
3803 struct rxparams *rxp;
3805 if (!afs_osi_suser(*acred))
3808 rxp = (struct rxparams *)ain;
3810 if (rxp->rx_initReceiveWindow)
3811 rx_initReceiveWindow = rxp->rx_initReceiveWindow;
3812 if (rxp->rx_maxReceiveWindow)
3813 rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
3814 if (rxp->rx_initSendWindow)
3815 rx_initSendWindow = rxp->rx_initSendWindow;
3816 if (rxp->rx_maxSendWindow)
3817 rx_maxSendWindow = rxp->rx_maxSendWindow;
3818 if (rxp->rxi_nSendFrags)
3819 rxi_nSendFrags = rxp->rxi_nSendFrags;
3820 if (rxp->rxi_nRecvFrags)
3821 rxi_nRecvFrags = rxp->rxi_nRecvFrags;
3822 if (rxp->rxi_OrphanFragSize)
3823 rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
3824 if (rxp->rx_maxReceiveSize) {
3825 rx_maxReceiveSize = rxp->rx_maxReceiveSize;
3826 rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
3828 if (rxp->rx_MyMaxSendSize)
3829 rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
3835 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
3839 * \param[in] ain not in use
3840 * \param[out] aout initial cache manager params
3842 * \retval E2BIG Error if the initial parameters are bigger than some PIGGYSIZE
3844 * \post return the initial cache manager parameters
3846 DECL_PIOCTL(PGetInitParams)
3848 if (sizeof(struct cm_initparams) > PIGGYSIZE)
3851 memcpy(aout, (char *)&cm_initParams, sizeof(struct cm_initparams));
3852 *aoutSize = sizeof(struct cm_initparams);
3856 #ifdef AFS_SGI65_ENV
3857 /* They took crget() from us, so fake it. */
3862 cr = crdup(get_current_cred());
3863 memset((char *)cr, 0, sizeof(cred_t));
3864 #if CELL || CELL_PREPARE
3872 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
3876 * \param[in] ain not in use
3877 * \param[out] aout value of cryptall
3879 * \post get the value of cryptall (presumably whether or not things should be encrypted)
3881 DECL_PIOCTL(PGetRxkcrypt)
3883 memcpy(aout, (char *)&cryptall, sizeof(afs_int32));
3884 *aoutSize = sizeof(afs_int32);
3889 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
3893 * \param[in] ain the argument whether or not things should be encrypted
3894 * \param[out] aout not in use
3896 * \retval EPERM Error if the user doesn't have super-user credentials
3897 * \retval EINVAL Error if the input is too big, or if the input is outside the bounds of what it can be set to
3899 * \post set whether or not things should be encrypted
3901 * \notes may need to be modified at a later date to take into account other values for cryptall (beyond true or false)
3903 DECL_PIOCTL(PSetRxkcrypt)
3907 if (!afs_osi_suser(*acred))
3909 if (ainSize != sizeof(afs_int32) || ain == NULL)
3911 memcpy((char *)&tmpval, ain, sizeof(afs_int32));
3912 /* if new mappings added later this will need to be changed */
3913 if (tmpval != 0 && tmpval != 1)
3919 #ifdef AFS_NEED_CLIENTCONTEXT
3921 * Create new credentials to correspond to a remote user with given
3922 * <hostaddr, uid, g0, g1>. This allows a server running as root to
3923 * provide pioctl (and other) services to foreign clients (i.e. nfs
3924 * clients) by using this call to `become' the client.
3927 #define PIOCTL_HEADER 6
3929 HandleClientContext(struct afs_ioctl *ablob, int *com,
3930 struct AFS_UCRED **acred, struct AFS_UCRED *credp)
3933 afs_uint32 hostaddr;
3934 afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
3935 struct afs_exporter *exporter, *outexporter;
3936 struct AFS_UCRED *newcred;
3937 struct unixuser *au;
3938 afs_uint32 comp = *com & 0xff00;
3941 #if defined(AFS_SGIMP_ENV)
3942 osi_Assert(ISAFS_GLOCK());
3944 AFS_STATCNT(HandleClientContext);
3945 if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
3946 /* Must at least include the PIOCTL_HEADER header words required by the protocol */
3947 return EINVAL; /* Too small to be good */
3949 ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
3950 AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
3952 osi_FreeLargeSpace(inData);
3956 /* Extract information for remote user */
3957 hostaddr = *((afs_uint32 *) ain);
3958 ain += sizeof(hostaddr);
3959 uid = *((afs_uint32 *) ain);
3961 g0 = *((afs_uint32 *) ain);
3963 g1 = *((afs_uint32 *) ain);
3965 *com = *((afs_uint32 *) ain);
3966 ain += sizeof(afs_int32);
3967 exporter_type = *((afs_uint32 *) ain); /* In case we support more than NFS */
3970 * Of course, one must be root for most of these functions, but
3971 * we'll allow (for knfs) you to set things if the pag is 0 and
3972 * you're setting tokens or unlogging.
3975 if (!afs_osi_suser(credp)) {
3976 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
3977 /* Since SGI's suser() returns explicit failure after the call.. */
3980 /* check for acceptable opcodes for normal folks, which are, so far,
3981 * get/set tokens, sysname, and unlog.
3983 if (i != 9 && i != 3 && i != 38 && i != 8) {
3984 osi_FreeLargeSpace(inData);
3989 ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
3990 ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
3991 osi_FreeLargeSpace(inData);
3994 * We map uid 0 to nobody to match the mapping that the nfs
3995 * server does and to ensure that the suser() calls in the afs
3996 * code fails for remote client roots.
3998 uid = afs_nobody; /* NFS_NOBODY == -2 */
4002 #ifdef AFS_AIX41_ENV
4005 newcred->cr_gid = isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ;
4006 #ifdef AFS_AIX51_ENV
4007 newcred->cr_groupset.gs_union.un_groups[0] = g0;
4008 newcred->cr_groupset.gs_union.un_groups[1] = g1;
4009 #elif defined(AFS_LINUX26_ENV)
4010 #ifdef AFS_LINUX26_ONEGROUP_ENV
4011 newcred->cr_group_info = groups_alloc(1); /* not that anything sets this */
4012 l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
4013 h = ((g0-0x3f00) >> 14);
4014 h = ((g1-0x3f00) >> 14) + h + h + h;
4015 GROUP_AT(newcred->cr_group_info, 0) = ((h << 28) | l);
4017 newcred->cr_group_info = groups_alloc(2);
4018 GROUP_AT(newcred->cr_group_info, 0) = g0;
4019 GROUP_AT(newcred->cr_group_info, 1) = g1;
4022 newcred->cr_groups[0] = g0;
4023 newcred->cr_groups[1] = g1;
4026 newcred->cr_ngrps = 2;
4027 #elif !defined(AFS_LINUX26_ENV)
4028 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
4029 newcred->cr_ngroups = 2;
4031 for (i = 2; i < NGROUPS; i++)
4032 newcred->cr_groups[i] = NOGROUP;
4035 #if !defined(AFS_OSF_ENV)
4036 afs_nfsclient_init(); /* before looking for exporter, ensure one exists */
4038 if (!(exporter = exporter_find(exporter_type))) {
4039 /* Exporter wasn't initialized or an invalid exporter type */
4043 if (exporter->exp_states & EXP_PWSYNC) {
4044 if (uid != credp->cr_uid) {
4046 return ENOEXEC; /* XXX Find a better errno XXX */
4049 newcred->cr_uid = uid; /* Only temporary */
4050 code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
4051 /* The client's pag is the only unique identifier for it */
4052 newcred->cr_uid = pag;
4054 if (!code && *com == PSETPAG) {
4055 /* Special case for 'setpag' */
4056 afs_uint32 pagvalue = genpag();
4058 au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
4060 * Note that we leave the 'outexporter' struct held so it won't
4063 au->exporter = outexporter;
4064 if (ablob->out_size >= 4) {
4065 AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
4068 afs_PutUser(au, WRITE_LOCK);
4071 return PSETPAG; /* Special return for setpag */
4073 EXP_RELE(outexporter);
4076 *com = (*com) | comp;
4079 #endif /* AFS_NEED_CLIENTCONTEXT */
4083 * VIOC_GETCPREFS (50) - Get client interface
4087 * \param[in] ain sprefrequest input
4088 * \param[out] aout spref information
4090 * \retval EIO Error if the afs daemon hasn't started yet
4091 * \retval EINVAL Error if some of the standard args aren't set
4093 * \post get all interface addresses and other information of the client interface
4095 DECL_PIOCTL(PGetCPrefs)
4097 struct sprefrequest *spin; /* input */
4098 struct sprefinfo *spout; /* output */
4099 struct spref *srvout; /* one output component */
4103 AFS_STATCNT(PGetCPrefs);
4104 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4105 return EIO; /* Inappropriate ioctl for device */
4107 if (ainSize < sizeof(struct sprefrequest))
4110 spin = (struct sprefrequest *)ain;
4111 spout = (struct sprefinfo *)aout;
4113 maxNumber = spin->num_servers; /* max addrs this time */
4114 srvout = spout->servers;
4116 ObtainReadLock(&afs_xinterface);
4118 /* copy out the client interface information from the
4119 ** kernel data structure "interface" to the output buffer
4121 for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
4122 && (j < maxNumber); i++, j++, srvout++)
4123 srvout->host.s_addr = afs_cb_interface.addr_in[i];
4125 spout->num_servers = j;
4126 *aoutSize = sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
4128 if (i >= afs_cb_interface.numberOfInterfaces)
4129 spout->next_offset = 0; /* start from beginning again */
4131 spout->next_offset = spin->offset + j;
4133 ReleaseReadLock(&afs_xinterface);
4138 * VIOC_SETCPREFS (51) - Set client interface
4142 * \param[in] ain the interfaces you want set
4143 * \param[out] aout not in use
4145 * \retval EIO Error if the afs daemon hasn't started yet
4146 * \retval EINVAL Error if the input is too large for the struct
4147 * \retval ENOMEM Error if there are too many servers
4149 * \post set the callbak interfaces addresses to those of the hosts
4151 DECL_PIOCTL(PSetCPrefs)
4153 struct setspref *sin;
4156 AFS_STATCNT(PSetCPrefs);
4157 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4158 return EIO; /* Inappropriate ioctl for device */
4160 sin = (struct setspref *)ain;
4162 if (ainSize < sizeof(struct setspref))
4164 #if 0 /* num_servers is unsigned */
4165 if (sin->num_servers < 0)
4168 if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
4171 ObtainWriteLock(&afs_xinterface, 412);
4172 afs_cb_interface.numberOfInterfaces = sin->num_servers;
4173 for (i = 0; (unsigned short)i < sin->num_servers; i++)
4174 afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
4176 ReleaseWriteLock(&afs_xinterface);
4181 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4185 * \param[in] ain the last part of a path to a mount point, which tells us what to flush
4186 * \param[out] aout not in use
4188 * \retval EINVAL Error if some of the initial arguments aren't set
4189 * \retval ENOTDIR Error if the initial argument for the mount point isn't a directory
4190 * \retval ENOENT Error if the dcache entry isn't set
4192 * \post remove all of the mount data from the dcache regarding a certain mount point
4194 DECL_PIOCTL(PFlushMount)
4196 register afs_int32 code;
4197 register struct vcache *tvc;
4198 register struct dcache *tdc;
4199 struct VenusFid tfid;
4201 struct sysname_info sysState;
4202 afs_size_t offset, len;
4204 AFS_STATCNT(PFlushMount);
4207 code = afs_VerifyVCache(avc, areq);
4210 if (vType(avc) != VDIR) {
4213 tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
4216 Check_AtSys(avc, ain, &sysState, areq);
4217 ObtainReadLock(&tdc->lock);
4219 code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
4220 } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
4221 ReleaseReadLock(&tdc->lock);
4222 afs_PutDCache(tdc); /* we're done with the data */
4223 bufp = sysState.name;
4227 tfid.Cell = avc->f.fid.Cell;
4228 tfid.Fid.Volume = avc->f.fid.Fid.Volume;
4229 if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
4230 tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
4232 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4238 if (tvc->mvstat != 1) {
4243 #ifdef AFS_BOZONLOCK_ENV
4244 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
4246 ObtainWriteLock(&tvc->lock, 649);
4247 ObtainWriteLock(&afs_xcbhash, 650);
4248 afs_DequeueCallback(tvc);
4249 tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
4250 ReleaseWriteLock(&afs_xcbhash);
4251 /* now find the disk cache entries */
4252 afs_TryToSmush(tvc, *acred, 1);
4253 osi_dnlc_purgedp(tvc);
4254 if (tvc->linkData && !(tvc->f.states & CCore)) {
4255 afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
4256 tvc->linkData = NULL;
4258 ReleaseWriteLock(&tvc->lock);
4259 #ifdef AFS_BOZONLOCK_ENV
4260 afs_BozonUnlock(&tvc->pvnLock, tvc);
4264 if (sysState.allocked)
4265 osi_FreeLargeSpace(bufp);
4270 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4274 * \param[in] ain the flags that control which stats to use
4275 * \param[out] aout not in use
4277 * \retval EACCES Error if the user doesn't have super-user credentials
4278 * \retval EINVAL Error if the flag input is too long
4280 * \post either enable process RPCStats, disable process RPCStats, or clear the process RPCStats
4282 DECL_PIOCTL(PRxStatProc)
4287 if (!afs_osi_suser(*acred)) {
4291 if (ainSize != sizeof(afs_int32)) {
4295 memcpy((char *)&flags, ain, sizeof(afs_int32));
4296 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4300 if (flags & AFSCALL_RXSTATS_ENABLE) {
4301 rx_enableProcessRPCStats();
4303 if (flags & AFSCALL_RXSTATS_DISABLE) {
4304 rx_disableProcessRPCStats();
4306 if (flags & AFSCALL_RXSTATS_CLEAR) {
4307 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
4316 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4320 * \param[in] ain the flags that control which statistics to use
4321 * \param[out] aout not in use
4323 * \retval EACCES Error if the user doesn't have super-user credentials
4324 * \retval EINVAL Error if the flag input is too long
4326 * \post either enable peer RPCStatws, disable peer RPCStats, or clear the peer RPCStats
4328 DECL_PIOCTL(PRxStatPeer)
4333 if (!afs_osi_suser(*acred)) {
4337 if (ainSize != sizeof(afs_int32)) {
4341 memcpy((char *)&flags, ain, sizeof(afs_int32));
4342 if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
4346 if (flags & AFSCALL_RXSTATS_ENABLE) {
4347 rx_enablePeerRPCStats();
4349 if (flags & AFSCALL_RXSTATS_DISABLE) {
4350 rx_disablePeerRPCStats();
4352 if (flags & AFSCALL_RXSTATS_CLEAR) {
4353 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
4360 DECL_PIOCTL(PPrefetchFromTape)
4362 register afs_int32 code, code1;
4364 struct afs_conn *tc;
4365 struct rx_call *tcall;
4366 struct AFSVolSync tsync;
4367 struct AFSFetchStatus OutStatus;
4368 struct AFSCallBack CallBack;
4369 struct VenusFid tfid;
4373 AFS_STATCNT(PSetAcl);
4377 if (ain && (ainSize == 3 * sizeof(afs_int32)))
4378 Fid = (struct AFSFid *)ain;
4380 Fid = &avc->f.fid.Fid;
4381 tfid.Cell = avc->f.fid.Cell;
4382 tfid.Fid.Volume = Fid->Volume;
4383 tfid.Fid.Vnode = Fid->Vnode;
4384 tfid.Fid.Unique = Fid->Unique;
4386 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4388 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4389 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
4392 afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
4393 ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
4396 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4400 tcall = rx_NewCall(tc->id);
4402 StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
4405 bytes = rx_Read(tcall, (char *)aout, sizeof(afs_int32));
4407 EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
4409 code1 = rx_EndCall(tcall, code);
4413 } while (afs_Analyze
4414 (tc, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
4415 SHARED_LOCK, NULL));
4416 /* This call is done only to have the callback things handled correctly */
4417 afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
4421 *aoutSize = sizeof(afs_int32);
4426 DECL_PIOCTL(PResidencyCmd)
4428 register afs_int32 code;
4429 struct afs_conn *tc;
4431 struct ResidencyCmdInputs *Inputs;
4432 struct ResidencyCmdOutputs *Outputs;
4433 struct VenusFid tfid;
4436 Inputs = (struct ResidencyCmdInputs *)ain;
4437 Outputs = (struct ResidencyCmdOutputs *)aout;
4440 if (!ain || ainSize != sizeof(struct ResidencyCmdInputs))
4445 Fid = &avc->f.fid.Fid;
4447 tfid.Cell = avc->f.fid.Cell;
4448 tfid.Fid.Volume = Fid->Volume;
4449 tfid.Fid.Vnode = Fid->Vnode;
4450 tfid.Fid.Unique = Fid->Unique;
4452 tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
4453 afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
4454 ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
4458 if (Inputs->command) {
4460 tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK);
4464 RXAFS_ResidencyCmd(tc->id, Fid, Inputs,
4465 (struct ResidencyCmdOutputs *)aout);
4469 } while (afs_Analyze
4470 (tc, code, &tvc->f.fid, areq,
4471 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
4472 /* This call is done to have the callback things handled correctly */
4473 afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4474 } else { /* just a status request, return also link data */
4476 Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
4477 Outputs->chars[0] = 0;
4478 if (vType(tvc) == VLNK) {
4479 ObtainWriteLock(&tvc->lock, 555);
4480 if (afs_HandleLink(tvc, areq) == 0)
4481 strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
4482 ReleaseWriteLock(&tvc->lock);
4489 *aoutSize = sizeof(struct ResidencyCmdOutputs);
4494 DECL_PIOCTL(PNewUuid)
4496 /*AFS_STATCNT(PNewUuid); */
4497 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4498 return EIO; /* Inappropriate ioctl for device */
4500 if (!afs_osi_suser(acred))
4503 ObtainWriteLock(&afs_xinterface, 555);
4504 afs_uuid_create(&afs_cb_interface.uuid);
4505 ReleaseWriteLock(&afs_xinterface);
4506 ForceAllNewConnections();
4510 #if defined(AFS_CACHE_BYPASS)
4512 DECL_PIOCTL(PSetCachingThreshold)
4517 setting = getting = 1;
4519 if (ain == NULL || ainSize < sizeof(afs_int32))
4525 if (setting == 0 && getting == 0)
4529 * If setting, set first, and return the value now in effect
4532 afs_int32 threshold;
4534 if (!afs_osi_suser(*acred))
4536 memcpy((char *)&threshold, ain, sizeof(afs_int32));
4537 cache_bypass_threshold = threshold;
4538 afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
4539 /* TODO: move to separate pioctl, or enhance pioctl */
4540 cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
4544 /* Return the current size threshold */
4545 afs_int32 oldThreshold = cache_bypass_threshold;
4546 memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
4547 *aoutSize = sizeof(afs_int32);
4553 #endif /* defined(AFS_CACHE_BYPASS) */
4555 DECL_PIOCTL(PCallBackAddr)
4558 afs_uint32 addr, code;
4562 struct afs_conn *tc;
4564 struct unixuser *tu;
4565 struct srvAddr **addrs;
4567 /*AFS_STATCNT(PCallBackAddr); */
4568 if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
4569 return EIO; /* Inappropriate ioctl for device */
4571 if (!afs_osi_suser(acred))
4574 if (ainSize < sizeof(afs_int32))
4577 memcpy(&addr, ain, sizeof(afs_int32));
4579 ObtainReadLock(&afs_xinterface);
4580 for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
4581 if (afs_cb_interface.addr_in[i] == addr)
4585 ReleaseWriteLock(&afs_xinterface);
4587 if (afs_cb_interface.addr_in[i] != addr)
4590 ObtainReadLock(&afs_xserver); /* Necessary? */
4591 ObtainReadLock(&afs_xsrvAddr);
4594 for (i = 0; i < NSERVERS; i++) {
4595 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4600 addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
4602 for (i = 0; i < NSERVERS; i++) {
4603 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
4604 if (j >= srvAddrCount)
4610 ReleaseReadLock(&afs_xsrvAddr);
4611 ReleaseReadLock(&afs_xserver);
4613 for (i = 0; i < j; i++) {
4619 /* vlserver has no callback conn */
4620 if (sa->sa_portal == AFS_VLPORT) {
4624 if (!ts->cell) /* not really an active server, anyway, it must */
4625 continue; /* have just been added by setsprefs */
4627 /* get a connection, even if host is down; bumps conn ref count */
4628 tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
4629 tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
4630 1 /*force */ , 1 /*create */ , SHARED_LOCK);
4631 afs_PutUser(tu, SHARED_LOCK);
4635 if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
4636 if (sa->sa_flags & SRVADDR_ISDOWN) {
4637 rx_SetConnDeadTime(tc->id, 3);
4639 #ifdef RX_ENABLE_LOCKS
4641 #endif /* RX_ENABLE_LOCKS */
4642 code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
4643 #ifdef RX_ENABLE_LOCKS
4645 #endif /* RX_ENABLE_LOCKS */
4647 afs_PutConn(tc, SHARED_LOCK); /* done with it now */
4648 } /* Outer loop over addrs */
4649 #endif /* UKERNEL */
4653 DECL_PIOCTL(PDiscon)
4655 #ifdef AFS_DISCON_ENV
4656 static afs_int32 mode = 1; /* Start up in 'off' */
4657 afs_int32 force = 0;
4662 if (!afs_osi_suser(*acred))
4668 afs_ConflictPolicy = ain[1] - 1;
4673 * All of these numbers are hard coded in fs.c. If they
4674 * change here, they should change there and vice versa
4677 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
4678 if (!AFS_IS_DISCONNECTED) {
4679 ObtainWriteLock(&afs_discon_lock, 999);
4680 afs_DisconGiveUpCallbacks();
4681 afs_RemoveAllConns();
4682 afs_is_disconnected = 1;
4683 afs_is_discon_rw = 1;
4684 ReleaseWriteLock(&afs_discon_lock);
4687 case 1: /* Fully connected, ("online" mode). */
4688 ObtainWriteLock(&afs_discon_lock, 998);
4691 afs_MarkAllServersUp();
4692 code = afs_ResyncDisconFiles(areq, *acred);
4695 if (code && !force) {
4696 printf("Files not synchronized properly, still in discon state. \n"
4697 "Please retry or use \"force\".\n");
4701 afs_DisconDiscardAll(*acred);
4703 afs_is_disconnected = 0;
4704 afs_is_discon_rw = 0;
4705 printf("\nSync succeeded. You are back online.\n");
4707 afs_ClearAllStatdFlag();
4709 ReleaseWriteLock(&afs_discon_lock);
4718 memcpy(aout, &mode, sizeof(afs_int32));
4719 *aoutSize = sizeof(afs_int32);
4726 DECL_PIOCTL(PNFSNukeCreds)
4728 afs_uint32 addr, code;
4729 register afs_int32 i;
4730 register struct unixuser *tu;
4732 AFS_STATCNT(PUnlog);
4733 if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
4734 return EIO; /* Inappropriate ioctl for device */
4736 if (ainSize < sizeof(afs_int32))
4738 memcpy(&addr, ain, sizeof(afs_int32));
4740 if ((*acred)->cr_gid == RMTUSER_REQ_PRIV && !addr) {
4741 tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
4742 if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
4743 afs_PutUser(tu, SHARED_LOCK);
4746 afs_PutUser(tu, SHARED_LOCK);
4747 } else if (!afs_osi_suser(acred)) {
4751 ObtainWriteLock(&afs_xuser, 227);
4752 for (i = 0; i < NUSERS; i++) {
4753 for (tu = afs_users[i]; tu; tu = tu->next) {
4754 if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
4756 tu->states &= ~UHasTokens;
4757 /* security is not having to say you're sorry */
4758 memset((char *)&tu->ct, 0, sizeof(struct ClearToken));
4760 ReleaseWriteLock(&afs_xuser);
4761 afs_ResetUserConns(tu);
4763 ObtainWriteLock(&afs_xuser, 228);
4765 /* set the expire times to 0, causes
4766 * afs_GCUserData to remove this entry
4768 tu->ct.EndTimestamp = 0;
4770 #endif /* UKERNEL */
4774 ReleaseWriteLock(&afs_xuser);