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"
14 #include "afs/sysincludes.h" /* Standard vendor system headers */
16 #include "h/syscallargs.h"
19 #include "h/sysproto.h"
22 #include <sys/ioctl.h>
23 #include <sys/ioccom.h>
25 #include "afsincludes.h" /* Afs-based standard headers */
26 #include "afs/afs_stats.h" /* afs statistics */
28 #include "afs/afs_bypasscache.h"
29 #include "rx/rx_globals.h"
32 extern int afs_rmtsys_enable
;
33 struct VenusFid afs_rootFid
;
34 afs_int32 afs_waitForever
= 0;
35 short afs_waitForeverCount
= 0;
36 afs_int32 afs_showflags
= GAGUSER
| GAGCONSOLE
; /* show all messages */
38 afs_int32 afs_is_disconnected
;
39 afs_int32 afs_is_discon_rw
;
40 /* On reconnection, turn this knob on until it finishes,
43 afs_int32 afs_in_sync
= 0;
51 * A set of handy little functions for encoding and decoding
52 * pioctls without losing your marbles, or memory integrity
56 afs_pd_alloc(struct afs_pdata
*apd
, size_t size
)
58 /* Ensure that we give caller at least one trailing guard byte
59 * for the NUL terminator. */
60 if (size
>= AFS_LRALLOCSIZ
)
61 apd
->ptr
= osi_Alloc(size
+ 1);
63 apd
->ptr
= osi_AllocLargeSpace(AFS_LRALLOCSIZ
);
68 /* Clear it all now, including the guard byte. */
69 if (size
>= AFS_LRALLOCSIZ
)
70 memset(apd
->ptr
, 0, size
+ 1);
72 memset(apd
->ptr
, 0, AFS_LRALLOCSIZ
);
74 /* Don't tell the caller about the guard byte. */
75 apd
->remaining
= size
;
81 afs_pd_free(struct afs_pdata
*apd
)
86 if (apd
->remaining
>= AFS_LRALLOCSIZ
)
87 osi_Free(apd
->ptr
, apd
->remaining
+ 1);
89 osi_FreeLargeSpace(apd
->ptr
);
96 afs_pd_where(struct afs_pdata
*apd
)
98 return apd
? apd
->ptr
: NULL
;
102 afs_pd_remaining(struct afs_pdata
*apd
)
104 return apd
? apd
->remaining
: 0;
108 afs_pd_skip(struct afs_pdata
*apd
, size_t skip
)
110 if (apd
== NULL
|| apd
->remaining
< skip
)
112 apd
->remaining
-= skip
;
119 afs_pd_getBytes(struct afs_pdata
*apd
, void *dest
, size_t bytes
)
121 if (apd
== NULL
|| apd
->remaining
< bytes
)
123 apd
->remaining
-= bytes
;
124 memcpy(dest
, apd
->ptr
, bytes
);
130 afs_pd_getInt(struct afs_pdata
*apd
, afs_int32
*val
)
132 return afs_pd_getBytes(apd
, val
, sizeof(*val
));
136 afs_pd_getUint(struct afs_pdata
*apd
, afs_uint32
*val
)
138 return afs_pd_getBytes(apd
, val
, sizeof(*val
));
142 afs_pd_inline(struct afs_pdata
*apd
, size_t bytes
)
146 if (apd
== NULL
|| apd
->remaining
< bytes
)
151 apd
->remaining
-= bytes
;
158 afs_pd_xdrStart(struct afs_pdata
*apd
, XDR
*xdrs
, enum xdr_op op
) {
159 xdrmem_create(xdrs
, apd
->ptr
, apd
->remaining
, op
);
163 afs_pd_xdrEnd(struct afs_pdata
*apd
, XDR
*xdrs
) {
166 pos
= xdr_getpos(xdrs
);
168 apd
->remaining
-= pos
;
175 afs_pd_getString(struct afs_pdata
*apd
, char *str
, size_t maxLen
)
179 if (apd
== NULL
|| apd
->remaining
<= 0)
181 len
= strlen(apd
->ptr
) + 1;
184 memcpy(str
, apd
->ptr
, len
);
186 apd
->remaining
-= len
;
191 afs_pd_getStringPtr(struct afs_pdata
*apd
, char **str
)
195 if (apd
== NULL
|| apd
->remaining
<= 0)
197 len
= strlen(apd
->ptr
) + 1;
200 apd
->remaining
-= len
;
205 afs_pd_putBytes(struct afs_pdata
*apd
, const void *bytes
, size_t len
)
207 if (apd
== NULL
|| apd
->remaining
< len
)
209 memcpy(apd
->ptr
, bytes
, len
);
211 apd
->remaining
-= len
;
216 afs_pd_putInt(struct afs_pdata
*apd
, afs_int32 val
)
218 return afs_pd_putBytes(apd
, &val
, sizeof(val
));
222 afs_pd_putString(struct afs_pdata
*apd
, char *str
) {
224 /* Add 1 so we copy the NULL too */
225 return afs_pd_putBytes(apd
, str
, strlen(str
) +1);
229 * \defgroup pioctl Path IOCTL functions
231 * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
234 * the AFS vcache structure in use by pioctl
238 * the AFS vrequest structure
240 * an afs_pdata block describing the data received from the caller
242 * an afs_pdata block describing a pre-allocated block for output
244 * UNIX credentials structure underlying the operation
247 #define DECL_PIOCTL(x) \
248 static int x(struct vcache *avc, int afun, struct vrequest *areq, \
249 struct afs_pdata *ain, struct afs_pdata *aout, \
252 /* Prototypes for pioctl routines */
253 DECL_PIOCTL(PGetFID
);
254 DECL_PIOCTL(PSetAcl
);
255 DECL_PIOCTL(PStoreBehind
);
256 DECL_PIOCTL(PGCPAGs
);
257 DECL_PIOCTL(PGetAcl
);
260 DECL_PIOCTL(PGetFileCell
);
261 DECL_PIOCTL(PGetWSCell
);
262 DECL_PIOCTL(PGetUserCell
);
263 DECL_PIOCTL(PSetTokens
);
264 DECL_PIOCTL(PSetTokens2
);
265 DECL_PIOCTL(PGetVolumeStatus
);
266 DECL_PIOCTL(PSetVolumeStatus
);
268 DECL_PIOCTL(PNewStatMount
);
269 DECL_PIOCTL(PGetTokens
);
270 DECL_PIOCTL(PGetTokens2
);
272 DECL_PIOCTL(PMariner
);
273 DECL_PIOCTL(PCheckServers
);
274 DECL_PIOCTL(PCheckVolNames
);
275 DECL_PIOCTL(PCheckAuth
);
276 DECL_PIOCTL(PFindVolume
);
277 DECL_PIOCTL(PViceAccess
);
278 DECL_PIOCTL(PSetCacheSize
);
279 DECL_PIOCTL(PGetCacheSize
);
280 DECL_PIOCTL(PRemoveCallBack
);
281 DECL_PIOCTL(PNewCell
);
282 DECL_PIOCTL(PNewAlias
);
283 DECL_PIOCTL(PListCells
);
284 DECL_PIOCTL(PListAliases
);
285 DECL_PIOCTL(PRemoveMount
);
286 DECL_PIOCTL(PGetCellStatus
);
287 DECL_PIOCTL(PSetCellStatus
);
288 DECL_PIOCTL(PFlushVolumeData
);
289 DECL_PIOCTL(PFlushAllVolumeData
);
290 DECL_PIOCTL(PGetVnodeXStatus
);
291 DECL_PIOCTL(PGetVnodeXStatus2
);
292 DECL_PIOCTL(PSetSysName
);
293 DECL_PIOCTL(PSetSPrefs
);
294 DECL_PIOCTL(PSetSPrefs33
);
295 DECL_PIOCTL(PGetSPrefs
);
296 DECL_PIOCTL(PExportAfs
);
298 DECL_PIOCTL(PTwiddleRx
);
299 DECL_PIOCTL(PGetInitParams
);
300 DECL_PIOCTL(PGetRxkcrypt
);
301 DECL_PIOCTL(PSetRxkcrypt
);
302 DECL_PIOCTL(PGetCPrefs
);
303 DECL_PIOCTL(PSetCPrefs
);
304 DECL_PIOCTL(PFlushMount
);
305 DECL_PIOCTL(PRxStatProc
);
306 DECL_PIOCTL(PRxStatPeer
);
307 DECL_PIOCTL(PPrefetchFromTape
);
309 DECL_PIOCTL(PCallBackAddr
);
310 DECL_PIOCTL(PDiscon
);
311 DECL_PIOCTL(PNFSNukeCreds
);
312 DECL_PIOCTL(PNewUuid
);
313 DECL_PIOCTL(PPrecache
);
314 DECL_PIOCTL(PGetPAG
);
315 #if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
316 DECL_PIOCTL(PSetCachingThreshold
);
320 * A macro that says whether we're going to need HandleClientContext().
321 * This is currently used only by the nfs translator.
323 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
324 #define AFS_NEED_CLIENTCONTEXT
327 /* Prototypes for private routines */
328 #ifdef AFS_NEED_CLIENTCONTEXT
329 static int HandleClientContext(struct afs_ioctl
*ablob
, int *com
,
333 int HandleIoctl(struct vcache
*avc
, afs_int32 acom
,
334 struct afs_ioctl
*adata
);
335 int afs_HandlePioctl(struct vnode
*avp
, afs_int32 acom
,
336 struct afs_ioctl
*ablob
, int afollow
,
337 afs_ucred_t
**acred
);
338 static int Prefetch(uparmtype apath
, struct afs_ioctl
*adata
, int afollow
,
341 typedef int (*pioctlFunction
) (struct vcache
*, int, struct vrequest
*,
342 struct afs_pdata
*, struct afs_pdata
*,
345 static pioctlFunction VpioctlSw
[] = {
350 PGetVolumeStatus
, /* 4 */
351 PSetVolumeStatus
, /* 5 */
356 PCheckServers
, /* 10 */
357 PCheckVolNames
, /* 11 */
359 PBogus
, /* 13 -- used to be quick check time */
360 PFindVolume
, /* 14 */
361 PBogus
, /* 15 -- prefetch is now special-cased; see pioctl code! */
362 PBogus
, /* 16 -- used to be testing code */
363 PNoop
, /* 17 -- used to be enable group */
364 PNoop
, /* 18 -- used to be disable group */
365 PBogus
, /* 19 -- used to be list group */
366 PViceAccess
, /* 20 */
367 PUnlog
, /* 21 -- unlog *is* unpag in this system */
368 PGetFID
, /* 22 -- get file ID */
369 PBogus
, /* 23 -- used to be waitforever */
370 PSetCacheSize
, /* 24 */
371 PRemoveCallBack
, /* 25 -- flush only the callback */
374 PRemoveMount
, /* 28 -- delete mount point */
375 PNewStatMount
, /* 29 -- new style mount point stat */
376 PGetFileCell
, /* 30 -- get cell name for input file */
377 PGetWSCell
, /* 31 -- get cell name for workstation */
378 PMariner
, /* 32 - set/get mariner host */
379 PGetUserCell
, /* 33 -- get cell name for user */
380 PBogus
, /* 34 -- Enable/Disable logging */
381 PGetCellStatus
, /* 35 */
382 PSetCellStatus
, /* 36 */
383 PFlushVolumeData
, /* 37 -- flush all data from a volume */
384 PSetSysName
, /* 38 - Set system name */
385 PExportAfs
, /* 39 - Export Afs to remote nfs clients */
386 PGetCacheSize
, /* 40 - get cache size and usage */
387 PGetVnodeXStatus
, /* 41 - get vcache's special status */
388 PSetSPrefs33
, /* 42 - Set CM Server preferences... */
389 PGetSPrefs
, /* 43 - Get CM Server preferences... */
390 PGag
, /* 44 - turn off/on all CM messages */
391 PTwiddleRx
, /* 45 - adjust some RX params */
392 PSetSPrefs
, /* 46 - Set CM Server preferences... */
393 PStoreBehind
, /* 47 - set degree of store behind to be done */
394 PGCPAGs
, /* 48 - disable automatic pag gc-ing */
395 PGetInitParams
, /* 49 - get initial cm params */
396 PGetCPrefs
, /* 50 - get client interface addresses */
397 PSetCPrefs
, /* 51 - set client interface addresses */
398 PFlushMount
, /* 52 - flush mount symlink data */
399 PRxStatProc
, /* 53 - control process RX statistics */
400 PRxStatPeer
, /* 54 - control peer RX statistics */
401 PGetRxkcrypt
, /* 55 -- Get rxkad encryption flag */
402 PSetRxkcrypt
, /* 56 -- Set rxkad encryption flag */
403 PBogus
, /* 57 -- arla: set file prio */
404 PBogus
, /* 58 -- arla: fallback getfh */
405 PBogus
, /* 59 -- arla: fallback fhopen */
406 PBogus
, /* 60 -- arla: controls xfsdebug */
407 PBogus
, /* 61 -- arla: controls arla debug */
408 PBogus
, /* 62 -- arla: debug interface */
409 PBogus
, /* 63 -- arla: print xfs status */
410 PBogus
, /* 64 -- arla: force cache check */
411 PBogus
, /* 65 -- arla: break callback */
412 PPrefetchFromTape
, /* 66 -- MR-AFS: prefetch file from tape */
413 PFsCmd
, /* 67 -- RXOSD: generic commnd interface */
414 PBogus
, /* 68 -- arla: fetch stats */
415 PGetVnodeXStatus2
, /* 69 - get caller access and some vcache status */
418 static pioctlFunction CpioctlSw
[] = {
420 PNewAlias
, /* 1 -- create new cell alias */
421 PListAliases
, /* 2 -- list cell aliases */
422 PCallBackAddr
, /* 3 -- request addr for callback rxcon */
424 PDiscon
, /* 5 -- get/set discon mode */
433 PFlushAllVolumeData
, /* 14 */
436 static pioctlFunction OpioctlSw
[] = {
438 PNFSNukeCreds
, /* 1 -- nuke all creds for NFS client */
439 #if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
440 PSetCachingThreshold
/* 2 -- get/set cache-bypass size threshold */
442 PNoop
/* 2 -- get/set cache-bypass size threshold */
446 #define PSetClientContext 99 /* Special pioctl to setup caller's creds */
447 int afs_nobody
= NFS_NOBODY
;
450 HandleIoctl(struct vcache
*avc
, afs_int32 acom
,
451 struct afs_ioctl
*adata
)
456 AFS_STATCNT(HandleIoctl
);
458 switch (acom
& 0xff) {
460 avc
->f
.states
|= CSafeStore
;
462 /* SXW - Should we force a MetaData flush for this flag setting */
465 /* case 2 used to be abort store, but this is no longer provided,
466 * since it is impossible to implement under normal Unix.
470 /* return the name of the cell this file is open on */
474 tcell
= afs_GetCell(avc
->f
.fid
.Cell
, READ_LOCK
);
476 i
= strlen(tcell
->cellName
) + 1; /* bytes to copy out */
478 if (i
> adata
->out_size
) {
479 /* 0 means we're not interested in the output */
480 if (adata
->out_size
!= 0)
484 AFS_COPYOUT(tcell
->cellName
, adata
->out
, i
, code
);
486 afs_PutCell(tcell
, READ_LOCK
);
492 case 49: /* VIOC_GETINITPARAMS */
493 if (adata
->out_size
< sizeof(struct cm_initparams
)) {
496 AFS_COPYOUT(&cm_initParams
, adata
->out
,
497 sizeof(struct cm_initparams
), code
);
509 return code
; /* so far, none implemented */
513 /* For aix we don't temporarily bypass ioctl(2) but rather do our
514 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
515 * is now called from afs_gn_ioctl.
518 afs_ioctl(struct vcache
*tvc
, int cmd
, int arg
)
520 struct afs_ioctl data
;
523 AFS_STATCNT(afs_ioctl
);
524 if (((cmd
>> 8) & 0xff) == 'V') {
525 /* This is a VICEIOCTL call */
526 AFS_COPYIN(arg
, (caddr_t
) & data
, sizeof(data
), error
);
529 error
= HandleIoctl(tvc
, cmd
, &data
);
532 /* No-op call; just return. */
536 # if defined(AFS_AIX32_ENV)
537 # if defined(AFS_AIX51_ENV)
540 kioctl(int fdes
, int com
, caddr_t arg
, caddr_t ext
, caddr_t arg2
,
542 # else /* __64BIT__ */
544 kioctl32(int fdes
, int com
, caddr_t arg
, caddr_t ext
, caddr_t arg2
,
546 # endif /* __64BIT__ */
549 kioctl(int fdes
, int com
, caddr_t arg
, caddr_t ext
)
550 # endif /* AFS_AIX51_ENV */
555 # ifdef AFS_AIX51_ENV
558 } u_uap
, *uap
= &u_uap
;
561 int ioctlDone
= 0, code
= 0;
563 AFS_STATCNT(afs_xioctl
);
567 # ifdef AFS_AIX51_ENV
571 if (setuerror(getf(uap
->fd
, &fd
))) {
574 if (fd
->f_type
== DTYPE_VNODE
) {
575 /* good, this is a vnode; next see if it is an AFS vnode */
576 tvc
= VTOAFS(fd
->f_vnode
); /* valid, given a vnode */
577 if (tvc
&& IsAfsVnode(AFSTOV(tvc
))) {
578 /* This is an AFS vnode */
579 if (((uap
->com
>> 8) & 0xff) == 'V') {
580 struct afs_ioctl
*datap
;
582 datap
= osi_AllocSmallSpace(AFS_SMALLOCSIZ
);
583 code
=copyin_afs_ioctl((char *)uap
->arg
, datap
);
585 osi_FreeSmallSpace(datap
);
587 # if defined(AFS_AIX41_ENV)
590 return (setuerror(code
), code
);
592 code
= HandleIoctl(tvc
, uap
->com
, datap
);
593 osi_FreeSmallSpace(datap
);
596 # if defined(AFS_AIX41_ENV)
603 # if defined(AFS_AIX41_ENV)
605 # if defined(AFS_AIX51_ENV)
607 code
= okioctl(fdes
, com
, arg
, ext
, arg2
, arg3
);
608 # else /* __64BIT__ */
609 code
= okioctl32(fdes
, com
, arg
, ext
, arg2
, arg3
);
610 # endif /* __64BIT__ */
611 # else /* !AFS_AIX51_ENV */
612 code
= okioctl(fdes
, com
, arg
, ext
);
613 # endif /* AFS_AIX51_ENV */
615 # elif defined(AFS_AIX32_ENV)
616 okioctl(fdes
, com
, arg
, ext
);
619 # if defined(KERNEL_HAVE_UERROR)
622 # if !defined(AFS_AIX41_ENV)
623 return (getuerror()? -1 : u
.u_ioctlrv
);
625 return getuerror()? -1 : 0;
632 #elif defined(AFS_SGI_ENV)
633 # if defined(AFS_SGI65_ENV)
634 afs_ioctl(OSI_VN_DECL(tvc
), int cmd
, void *arg
, int flag
, cred_t
* cr
,
635 rval_t
* rvalp
, struct vopbd
* vbds
)
637 afs_ioctl(OSI_VN_DECL(tvc
), int cmd
, void *arg
, int flag
, cred_t
* cr
,
638 rval_t
* rvalp
, struct vopbd
* vbds
)
641 struct afs_ioctl data
;
647 AFS_STATCNT(afs_ioctl
);
648 if (((cmd
>> 8) & 0xff) == 'V') {
649 /* This is a VICEIOCTL call */
650 error
= copyin_afs_ioctl(arg
, &data
);
653 locked
= ISAFS_GLOCK();
656 error
= HandleIoctl(tvc
, cmd
, &data
);
661 /* No-op call; just return. */
665 #elif defined(AFS_SUN5_ENV)
666 struct afs_ioctl_sys
{
673 afs_xioctl(struct afs_ioctl_sys
*uap
, rval_t
*rvp
)
677 int ioctlDone
= 0, code
= 0;
679 AFS_STATCNT(afs_xioctl
);
683 if (fd
->f_vnode
->v_type
== VREG
|| fd
->f_vnode
->v_type
== VDIR
) {
684 tvc
= VTOAFS(fd
->f_vnode
); /* valid, given a vnode */
685 if (tvc
&& IsAfsVnode(AFSTOV(tvc
))) {
686 /* This is an AFS vnode */
687 if (((uap
->com
>> 8) & 0xff) == 'V') {
688 struct afs_ioctl
*datap
;
690 datap
= osi_AllocSmallSpace(AFS_SMALLOCSIZ
);
691 code
=copyin_afs_ioctl((char *)uap
->arg
, datap
);
693 osi_FreeSmallSpace(datap
);
698 code
= HandleIoctl(tvc
, uap
->com
, datap
);
699 osi_FreeSmallSpace(datap
);
707 code
= ioctl(uap
, rvp
);
711 #elif defined(AFS_LINUX22_ENV)
712 struct afs_ioctl_sys
{
717 afs_xioctl(struct inode
*ip
, struct file
*fp
, unsigned int com
,
720 struct afs_ioctl_sys ua
, *uap
= &ua
;
724 AFS_STATCNT(afs_xioctl
);
729 if (tvc
&& IsAfsVnode(AFSTOV(tvc
))) {
730 /* This is an AFS vnode */
731 if (((uap
->com
>> 8) & 0xff) == 'V') {
732 struct afs_ioctl
*datap
;
734 datap
= osi_AllocSmallSpace(AFS_SMALLOCSIZ
);
735 code
= copyin_afs_ioctl((char *)uap
->arg
, datap
);
737 osi_FreeSmallSpace(datap
);
741 code
= HandleIoctl(tvc
, uap
->com
, datap
);
742 osi_FreeSmallSpace(datap
);
750 #elif defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV)
758 afs_xioctl(afs_proc_t
*p
, struct ioctl_args
*uap
, register_t
*retval
)
762 int ioctlDone
= 0, code
= 0;
764 AFS_STATCNT(afs_xioctl
);
765 if ((code
= fdgetf(p
, uap
->fd
, &fd
)))
767 if (fd
->f_type
== DTYPE_VNODE
) {
768 tvc
= VTOAFS((struct vnode
*)fd
->f_data
); /* valid, given a vnode */
769 if (tvc
&& IsAfsVnode(AFSTOV(tvc
))) {
770 /* This is an AFS vnode */
771 if (((uap
->com
>> 8) & 0xff) == 'V') {
772 struct afs_ioctl
*datap
;
774 datap
= osi_AllocSmallSpace(AFS_SMALLOCSIZ
);
775 code
= copyin_afs_ioctl((char *)uap
->arg
, datap
);
777 osi_FreeSmallSpace(datap
);
781 code
= HandleIoctl(tvc
, uap
->com
, datap
);
782 osi_FreeSmallSpace(datap
);
790 return ioctl(p
, uap
, retval
);
794 #elif defined(AFS_XBSD_ENV)
795 # if defined(AFS_FBSD_ENV)
798 afs_xioctl(struct thread
*td
, struct ioctl_args
*uap
,
801 afs_proc_t
*p
= td
->td_proc
;
802 # elif defined(AFS_NBSD_ENV)
804 afs_xioctl(afs_proc_t
*p
, const struct sys_ioctl_args
*uap
, register_t
*retval
)
814 afs_xioctl(afs_proc_t
*p
, const struct ioctl_args
*uap
, register_t
*retval
)
817 struct filedesc
*fdp
;
819 int ioctlDone
= 0, code
= 0;
822 AFS_STATCNT(afs_xioctl
);
823 #if defined(AFS_NBSD40_ENV)
824 fdp
= p
->l_proc
->p_fd
;
828 #if defined(AFS_NBSD50_ENV)
829 if ((fd
= fd_getfile(SCARG(uap
, fd
))) == NULL
)
831 #elif defined(AFS_FBSD100_ENV)
832 if ((uap
->fd
>= fdp
->fd_nfiles
)
833 || ((fd
= fdp
->fd_ofiles
[uap
->fd
].fde_file
) == NULL
))
836 if ((uap
->fd
>= fdp
->fd_nfiles
)
837 || ((fd
= fdp
->fd_ofiles
[uap
->fd
]) == NULL
))
840 if ((fd
->f_flag
& (FREAD
| FWRITE
)) == 0)
842 /* first determine whether this is any sort of vnode */
843 if (fd
->f_type
== DTYPE_VNODE
) {
844 /* good, this is a vnode; next see if it is an AFS vnode */
845 # if defined(AFS_OBSD_ENV)
847 IsAfsVnode((struct vnode
*)fd
->
848 f_data
) ? VTOAFS((struct vnode
*)fd
->f_data
) : NULL
;
850 tvc
= VTOAFS((struct vnode
*)fd
->f_data
); /* valid, given a vnode */
852 if (tvc
&& IsAfsVnode((struct vnode
*)fd
->f_data
)) {
853 /* This is an AFS vnode */
854 #if defined(AFS_NBSD50_ENV)
855 if (((SCARG(uap
, com
) >> 8) & 0xff) == 'V') {
857 if (((uap
->com
>> 8) & 0xff) == 'V') {
859 struct afs_ioctl
*datap
;
861 datap
= osi_AllocSmallSpace(AFS_SMALLOCSIZ
);
862 #if defined(AFS_NBSD50_ENV)
863 code
= copyin_afs_ioctl(SCARG(uap
, data
), datap
);
865 code
= copyin_afs_ioctl((char *)uap
->arg
, datap
);
868 osi_FreeSmallSpace(datap
);
872 #if defined(AFS_NBSD50_ENV)
873 code
= HandleIoctl(tvc
, SCARG(uap
, com
), datap
);
875 code
= HandleIoctl(tvc
, uap
->com
, datap
);
877 osi_FreeSmallSpace(datap
);
884 #if defined(AFS_NBSD50_ENV)
885 fd_putfile(SCARG(uap
, fd
));
889 # if defined(AFS_FBSD_ENV)
890 # if (__FreeBSD_version >= 900044)
891 return sys_ioctl(td
, uap
);
893 return ioctl(td
, uap
);
895 # elif defined(AFS_OBSD_ENV)
896 code
= sys_ioctl(p
, uap
, retval
);
897 # elif defined(AFS_NBSD_ENV)
898 code
= sys_ioctl(p
, uap
, retval
);
904 #elif defined(UKERNEL)
912 } *uap
= (struct a
*)get_user_struct()->u_ap
;
915 int ioctlDone
= 0, code
= 0;
917 AFS_STATCNT(afs_xioctl
);
922 /* first determine whether this is any sort of vnode */
923 if (fd
->f_type
== DTYPE_VNODE
) {
924 /* good, this is a vnode; next see if it is an AFS vnode */
925 tvc
= VTOAFS((struct vnode
*)fd
->f_data
); /* valid, given a vnode */
926 if (tvc
&& IsAfsVnode(AFSTOV(tvc
))) {
927 /* This is an AFS vnode */
928 if (((uap
->com
>> 8) & 0xff) == 'V') {
929 struct afs_ioctl
*datap
;
931 datap
= osi_AllocSmallSpace(AFS_SMALLOCSIZ
);
932 code
=copyin_afs_ioctl((char *)uap
->arg
, datap
);
934 osi_FreeSmallSpace(datap
);
937 return (setuerror(code
), code
);
939 code
= HandleIoctl(tvc
, uap
->com
, datap
);
940 osi_FreeSmallSpace(datap
);
953 #endif /* AFS_HPUX102_ENV */
955 #if defined(AFS_SGI_ENV)
956 /* "pioctl" system call entry point; just pass argument to the parameterized
965 afs_pioctl(struct pioctlargs
*uap
, rval_t
* rvp
)
969 AFS_STATCNT(afs_pioctl
);
971 code
= afs_syscall_pioctl(uap
->path
, uap
->cmd
, uap
->cmarg
, uap
->follow
);
973 # ifdef AFS_SGI64_ENV
980 #elif defined(AFS_FBSD_ENV)
982 afs_pioctl(struct thread
*td
, void *args
, int *retval
)
989 } *uap
= (struct a
*)args
;
991 AFS_STATCNT(afs_pioctl
);
992 return (afs_syscall_pioctl
993 (uap
->path
, uap
->cmd
, uap
->cmarg
, uap
->follow
, td
->td_ucred
));
996 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
998 afs_pioctl(afs_proc_t
*p
, void *args
, int *retval
)
1005 } *uap
= (struct a
*)args
;
1007 AFS_STATCNT(afs_pioctl
);
1008 # if defined(AFS_DARWIN80_ENV) || defined(AFS_NBSD40_ENV)
1009 return (afs_syscall_pioctl
1010 (uap
->path
, uap
->cmd
, uap
->cmarg
, uap
->follow
,
1013 return (afs_syscall_pioctl
1014 (uap
->path
, uap
->cmd
, uap
->cmarg
, uap
->follow
,
1015 # if defined(AFS_FBSD_ENV)
1018 p
->p_cred
->pc_ucred
));
1025 /* macro to avoid adding any more #ifdef's to pioctl code. */
1026 #if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
1027 #define PIOCTL_FREE_CRED() crfree(credp)
1029 #define PIOCTL_FREE_CRED()
1034 afs_syscall_pioctl(char *path
, unsigned int com
, caddr_t cmarg
, int follow
,
1035 rval_t
*vvp
, afs_ucred_t
*credp
)
1037 #ifdef AFS_DARWIN100_ENV
1038 afs_syscall64_pioctl(user_addr_t path
, unsigned int com
, user_addr_t cmarg
,
1039 int follow
, afs_ucred_t
*credp
)
1040 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1041 afs_syscall_pioctl(char *path
, unsigned int com
, caddr_t cmarg
, int follow
,
1044 afs_syscall_pioctl(char *path
, unsigned int com
, caddr_t cmarg
, int follow
)
1048 struct afs_ioctl data
;
1049 #ifdef AFS_NEED_CLIENTCONTEXT
1050 afs_ucred_t
*tmpcred
= NULL
;
1052 #if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1053 afs_ucred_t
*foreigncreds
= NULL
;
1056 struct vnode
*vp
= NULL
;
1057 #ifdef AFS_AIX41_ENV
1058 struct ucred
*credp
= crref(); /* don't free until done! */
1060 #ifdef AFS_LINUX22_ENV
1061 cred_t
*credp
= crref(); /* don't free until done! */
1065 AFS_STATCNT(afs_syscall_pioctl
);
1067 follow
= 1; /* compat. with old venus */
1068 code
= copyin_afs_ioctl(cmarg
, &data
);
1071 #if defined(KERNEL_HAVE_UERROR)
1076 if ((com
& 0xff) == PSetClientContext
) {
1077 #ifdef AFS_NEED_CLIENTCONTEXT
1078 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
1079 code
= HandleClientContext(&data
, &com
, &foreigncreds
, credp
);
1081 code
= HandleClientContext(&data
, &com
, &foreigncreds
, osi_curcred());
1085 crfree(foreigncreds
);
1088 #if defined(KERNEL_HAVE_UERROR)
1089 return (setuerror(code
), code
);
1094 #else /* AFS_NEED_CLIENTCONTEXT */
1096 #endif /* AFS_NEED_CLIENTCONTEXT */
1098 #ifdef AFS_NEED_CLIENTCONTEXT
1101 * We could have done without temporary setting the u.u_cred below
1102 * (foreigncreds could be passed as param the pioctl modules)
1103 * but calls such as afs_osi_suser() doesn't allow that since it
1104 * references u.u_cred directly. We could, of course, do something
1105 * like afs_osi_suser(cred) which, I think, is better since it
1106 * generalizes and supports multi cred environments...
1108 #if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
1110 credp
= foreigncreds
;
1111 #elif defined(AFS_AIX41_ENV)
1112 tmpcred
= crref(); /* XXX */
1113 crset(foreigncreds
);
1114 #elif defined(AFS_HPUX101_ENV)
1115 tmpcred
= p_cred(u
.u_procp
);
1116 set_p_cred(u
.u_procp
, foreigncreds
);
1117 #elif defined(AFS_SGI_ENV)
1118 tmpcred
= OSI_GET_CURRENT_CRED();
1119 OSI_SET_CURRENT_CRED(foreigncreds
);
1122 u
.u_cred
= foreigncreds
;
1125 #endif /* AFS_NEED_CLIENTCONTEXT */
1126 if ((com
& 0xff) == 15) {
1127 /* special case prefetch so entire pathname eval occurs in helper process.
1128 * otherwise, the pioctl call is essentially useless */
1129 #if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1131 Prefetch(path
, &data
, follow
,
1132 foreigncreds
? foreigncreds
: credp
);
1134 code
= Prefetch(path
, &data
, follow
, osi_curcred());
1137 #if defined(KERNEL_HAVE_UERROR)
1144 #ifdef AFS_AIX41_ENV
1146 lookupname(path
, USR
, follow
, NULL
, &vp
,
1147 foreigncreds
? foreigncreds
: credp
);
1149 #ifdef AFS_LINUX22_ENV
1150 code
= gop_lookupname_user(path
, AFS_UIOUSER
, follow
, &dp
);
1152 vp
= (struct vnode
*)dp
->d_inode
;
1154 code
= gop_lookupname_user(path
, AFS_UIOUSER
, follow
, &vp
);
1155 #endif /* AFS_LINUX22_ENV */
1156 #endif /* AFS_AIX41_ENV */
1160 #if defined(KERNEL_HAVE_UERROR)
1168 #if defined(AFS_SUN510_ENV)
1169 if (vp
&& !IsAfsVnode(vp
)) {
1170 struct vnode
*realvp
;
1172 #ifdef AFS_SUN511_ENV
1173 (VOP_REALVP(vp
, &realvp
, NULL
) == 0)
1175 (VOP_REALVP(vp
, &realvp
) == 0)
1178 struct vnode
*oldvp
= vp
;
1186 /* now make the call if we were passed no file, or were passed an AFS file */
1187 if (!vp
|| IsAfsVnode(vp
)) {
1188 #if defined(AFS_SUN5_ENV)
1189 code
= afs_HandlePioctl(vp
, com
, &data
, follow
, &credp
);
1190 #elif defined(AFS_AIX41_ENV)
1192 struct ucred
*cred1
, *cred2
;
1195 cred1
= cred2
= foreigncreds
;
1197 cred1
= cred2
= credp
;
1199 code
= afs_HandlePioctl(vp
, com
, &data
, follow
, &cred1
);
1200 if (cred1
!= cred2
) {
1201 /* something changed the creds */
1205 #elif defined(AFS_HPUX101_ENV)
1207 struct ucred
*cred
= p_cred(u
.u_procp
);
1208 code
= afs_HandlePioctl(vp
, com
, &data
, follow
, &cred
);
1210 #elif defined(AFS_SGI_ENV)
1213 credp
= OSI_GET_CURRENT_CRED();
1214 code
= afs_HandlePioctl(vp
, com
, &data
, follow
, &credp
);
1216 #elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1217 code
= afs_HandlePioctl(vp
, com
, &data
, follow
, &credp
);
1218 #elif defined(UKERNEL)
1219 code
= afs_HandlePioctl(vp
, com
, &data
, follow
,
1220 &(get_user_struct()->u_cred
));
1222 code
= afs_HandlePioctl(vp
, com
, &data
, follow
, &u
.u_cred
);
1225 #if defined(KERNEL_HAVE_UERROR)
1228 code
= EINVAL
; /* not in /afs */
1233 #if defined(AFS_NEED_CLIENTCONTEXT)
1235 #ifdef AFS_AIX41_ENV
1236 crset(tmpcred
); /* restore original credentials */
1238 #if defined(AFS_HPUX101_ENV)
1239 set_p_cred(u
.u_procp
, tmpcred
); /* restore original credentials */
1240 #elif defined(AFS_SGI_ENV)
1241 OSI_SET_CURRENT_CRED(tmpcred
); /* restore original credentials */
1242 #elif defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
1243 credp
= tmpcred
; /* restore original credentials */
1245 osi_curcred() = tmpcred
; /* restore original credentials */
1246 #endif /* AFS_HPUX101_ENV */
1247 crfree(foreigncreds
);
1250 #endif /* AFS_NEED_CLIENTCONTEXT */
1252 #ifdef AFS_LINUX22_ENV
1254 * Holding the global lock when calling dput can cause a deadlock
1255 * when the kernel calls back into afs_dentry_iput
1261 #if defined(AFS_FBSD80_ENV)
1262 if (VOP_ISLOCKED(vp
))
1264 #endif /* AFS_FBSD80_ENV */
1265 AFS_RELE(vp
); /* put vnode back */
1269 #if defined(KERNEL_HAVE_UERROR)
1272 return (getuerror());
1278 #ifdef AFS_DARWIN100_ENV
1280 afs_syscall_pioctl(char * path
, unsigned int com
, caddr_t cmarg
,
1281 int follow
, afs_ucred_t
*credp
)
1283 return afs_syscall64_pioctl(CAST_USER_ADDR_T(path
), com
,
1284 CAST_USER_ADDR_T((unsigned int)cmarg
), follow
,
1289 #define MAXPIOCTLTOKENLEN \
1290 (3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
1293 afs_HandlePioctl(struct vnode
*avp
, afs_int32 acom
,
1294 struct afs_ioctl
*ablob
, int afollow
,
1295 afs_ucred_t
**acred
)
1298 struct vrequest
*treq
= NULL
;
1300 afs_int32 function
, device
;
1301 struct afs_pdata input
, output
;
1302 struct afs_pdata copyInput
, copyOutput
;
1304 pioctlFunction
*pioctlSw
;
1306 struct afs_fakestat_state fakestate
;
1308 memset(&input
, 0, sizeof(input
));
1309 memset(&output
, 0, sizeof(output
));
1311 avc
= avp
? VTOAFS(avp
) : NULL
;
1312 afs_Trace3(afs_iclSetp
, CM_TRACE_PIOCTL
, ICL_TYPE_INT32
, acom
& 0xff,
1313 ICL_TYPE_POINTER
, avc
, ICL_TYPE_INT32
, afollow
);
1314 AFS_STATCNT(HandlePioctl
);
1316 code
= afs_CreateReq(&treq
, *acred
);
1320 afs_InitFakeStat(&fakestate
);
1322 code
= afs_EvalFakeStat(&avc
, &fakestate
, treq
);
1326 device
= (acom
& 0xff00) >> 8;
1328 case 'V': /* Original pioctls */
1329 pioctlSw
= VpioctlSw
;
1330 pioctlSwSize
= sizeof(VpioctlSw
);
1332 case 'C': /* Coordinated/common pioctls */
1333 pioctlSw
= CpioctlSw
;
1334 pioctlSwSize
= sizeof(CpioctlSw
);
1336 case 'O': /* Coordinated/common pioctls */
1337 pioctlSw
= OpioctlSw
;
1338 pioctlSwSize
= sizeof(OpioctlSw
);
1344 function
= acom
& 0xff;
1345 if (function
>= (pioctlSwSize
/ sizeof(char *))) {
1350 /* Do all range checking before continuing */
1351 if (ablob
->in_size
> MAXPIOCTLTOKENLEN
||
1352 ablob
->in_size
< 0 || ablob
->out_size
< 0) {
1357 code
= afs_pd_alloc(&input
, ablob
->in_size
);
1361 if (ablob
->in_size
> 0) {
1362 AFS_COPYIN(ablob
->in
, input
.ptr
, ablob
->in_size
, code
);
1363 input
.ptr
[input
.remaining
] = '\0';
1368 if ((function
== 8 && device
== 'V') ||
1369 (function
== 7 && device
== 'C')) { /* PGetTokens */
1370 code
= afs_pd_alloc(&output
, MAXPIOCTLTOKENLEN
);
1372 code
= afs_pd_alloc(&output
, AFS_LRALLOCSIZ
);
1378 copyOutput
= output
;
1381 (*pioctlSw
[function
]) (avc
, function
, treq
, ©Input
,
1382 ©Output
, acred
);
1384 outSize
= copyOutput
.ptr
- output
.ptr
;
1386 if (code
== 0 && ablob
->out_size
> 0) {
1387 if (outSize
> ablob
->out_size
) {
1388 code
= E2BIG
; /* data wont fit in user buffer */
1389 } else if (outSize
) {
1390 AFS_COPYOUT(output
.ptr
, ablob
->out
, outSize
, code
);
1395 afs_pd_free(&input
);
1396 afs_pd_free(&output
);
1398 afs_PutFakeStat(&fakestate
);
1399 code
= afs_CheckCode(code
, treq
, 41);
1400 afs_DestroyReq(treq
);
1405 * VIOCGETFID (22) - Get file ID quickly
1409 * \param[in] ain not in use
1410 * \param[out] aout fid of requested file
1412 * \retval EINVAL Error if some of the initial arguments aren't set
1414 * \post get the file id of some file
1416 DECL_PIOCTL(PGetFID
)
1418 AFS_STATCNT(PGetFID
);
1421 if (afs_pd_putBytes(aout
, &avc
->f
.fid
, sizeof(struct VenusFid
)) != 0)
1427 * VIOCSETAL (1) - Set access control list
1431 * \param[in] ain the ACL being set
1432 * \param[out] aout the ACL being set returned
1434 * \retval EINVAL Error if some of the standard args aren't set
1436 * \post Changed ACL, via direct writing to the wire
1439 dummy_PSetAcl(char *ain
, char *aout
)
1444 DECL_PIOCTL(PSetAcl
)
1447 struct afs_conn
*tconn
;
1448 struct AFSOpaque acl
;
1449 struct AFSVolSync tsync
;
1450 struct AFSFetchStatus OutStatus
;
1451 struct rx_connection
*rxconn
;
1454 AFS_STATCNT(PSetAcl
);
1458 if (afs_pd_getStringPtr(ain
, &acl
.AFSOpaque_val
) != 0)
1460 acl
.AFSOpaque_len
= strlen(acl
.AFSOpaque_val
) + 1;
1461 if (acl
.AFSOpaque_len
> 1024)
1465 tconn
= afs_Conn(&avc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
1467 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL
);
1470 RXAFS_StoreACL(rxconn
, (struct AFSFid
*)&avc
->f
.fid
.Fid
,
1471 &acl
, &OutStatus
, &tsync
);
1476 } while (afs_Analyze
1477 (tconn
, rxconn
, code
, &avc
->f
.fid
, areq
, AFS_STATS_FS_RPCIDX_STOREACL
,
1478 SHARED_LOCK
, NULL
));
1480 /* now we've forgotten all of the access info */
1481 afs_StaleVCacheFlags(avc
, AFS_STALEVC_CLEARCB
, CUnique
);
1483 /* SXW - Should we flush metadata here? */
1488 int afs_defaultAsynchrony
= 0;
1491 * VIOC_STOREBEHIND (47) Adjust store asynchrony
1495 * \param[in] ain sbstruct (store behind structure) input
1496 * \param[out] aout resulting sbstruct
1499 * Error if the user doesn't have super-user credentials
1501 * Error if there isn't enough access to not check the mode bits
1504 * Changes either the default asynchrony (the amount of data that
1505 * can remain to be written when the cache manager returns control
1506 * to the user), or the asyncrony for the specified file.
1508 DECL_PIOCTL(PStoreBehind
)
1510 struct sbstruct sbr
;
1512 if (afs_pd_getBytes(ain
, &sbr
, sizeof(struct sbstruct
)) != 0)
1515 if (sbr
.sb_default
!= -1) {
1516 if (afs_osi_suser(*acred
))
1517 afs_defaultAsynchrony
= sbr
.sb_default
;
1522 if (avc
&& (sbr
.sb_thisfile
!= -1)) {
1524 (avc
, PRSFS_WRITE
| PRSFS_ADMINISTER
, areq
, DONT_CHECK_MODE_BITS
))
1525 avc
->asynchrony
= sbr
.sb_thisfile
;
1530 memset(&sbr
, 0, sizeof(sbr
));
1531 sbr
.sb_default
= afs_defaultAsynchrony
;
1533 sbr
.sb_thisfile
= avc
->asynchrony
;
1536 return afs_pd_putBytes(aout
, &sbr
, sizeof(sbr
));
1540 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
1544 * \param[in] ain not in use
1545 * \param[out] aout not in use
1547 * \retval EACCES Error if the user doesn't have super-user credentials
1549 * \post set the gcpags to GCPAGS_USERDISABLED
1551 DECL_PIOCTL(PGCPAGs
)
1553 if (!afs_osi_suser(*acred
)) {
1556 afs_gcpags
= AFS_GCPAGS_USERDISABLED
;
1561 * VIOCGETAL (2) - Get access control list
1565 * \param[in] ain not in use
1566 * \param[out] aout the ACL
1568 * \retval EINVAL Error if some of the standard args aren't set
1569 * \retval ERANGE Error if the vnode of the file id is too large
1570 * \retval -1 Error if getting the ACL failed
1572 * \post Obtain the ACL, based on file ID
1575 * There is a hack to tell which type of ACL is being returned, checks
1576 * the top 2-bytes of the input size to judge what type of ACL it is,
1577 * only for dfs xlator ACLs
1579 DECL_PIOCTL(PGetAcl
)
1581 struct AFSOpaque acl
;
1582 struct AFSVolSync tsync
;
1583 struct AFSFetchStatus OutStatus
;
1585 struct afs_conn
*tconn
;
1587 struct rx_connection
*rxconn
;
1590 AFS_STATCNT(PGetAcl
);
1593 Fid
.Volume
= avc
->f
.fid
.Fid
.Volume
;
1594 Fid
.Vnode
= avc
->f
.fid
.Fid
.Vnode
;
1595 Fid
.Unique
= avc
->f
.fid
.Fid
.Unique
;
1596 if (avc
->f
.states
& CForeign
) {
1598 * For a dfs xlator acl we have a special hack so that the
1599 * xlator will distinguish which type of acl will return. So
1600 * we currently use the top 2-bytes (vals 0-4) to tell which
1601 * type of acl to bring back. Horrible hack but this will
1602 * cause the least number of changes to code size and interfaces.
1604 if (Fid
.Vnode
& 0xc0000000)
1606 Fid
.Vnode
|= (ain
->remaining
<< 30);
1608 acl
.AFSOpaque_val
= aout
->ptr
;
1610 tconn
= afs_Conn(&avc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
1612 acl
.AFSOpaque_val
[0] = '\0';
1613 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL
);
1615 code
= RXAFS_FetchACL(rxconn
, &Fid
, &acl
, &OutStatus
, &tsync
);
1620 } while (afs_Analyze
1621 (tconn
, rxconn
, code
, &avc
->f
.fid
, areq
, AFS_STATS_FS_RPCIDX_FETCHACL
,
1622 SHARED_LOCK
, NULL
));
1625 if (acl
.AFSOpaque_len
== 0)
1626 afs_pd_skip(aout
, 1); /* leave the NULL */
1628 afs_pd_skip(aout
, acl
.AFSOpaque_len
); /* Length of the ACL */
1634 * PNoop returns success. Used for functions which are not implemented
1635 * or are no longer in use.
1639 * \retval Always returns success
1642 * Functions involved in this:
1643 * 17 (VIOCENGROUP) -- used to be enable group;
1644 * 18 (VIOCDISGROUP) -- used to be disable group;
1645 * 2 (?) -- get/set cache-bypass size threshold
1654 * PBogus returns fail. Used for functions which are not implemented or
1655 * are no longer in use.
1659 * \retval EINVAL Always returns this value
1662 * Functions involved in this:
1668 * 13 (VIOCGETTIME) -- used to be quick check time;
1669 * 15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!;
1670 * 16 (VIOCNOP) -- used to be testing code;
1671 * 19 (VIOCLISTGROUPS) -- used to be list group;
1672 * 23 (VIOCWAITFOREVER) -- used to be waitforever;
1673 * 57 (VIOC_FPRIOSTATUS) -- arla: set file prio;
1674 * 58 (VIOC_FHGET) -- arla: fallback getfh;
1675 * 59 (VIOC_FHOPEN) -- arla: fallback fhopen;
1676 * 60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug;
1677 * 61 (VIOC_ARLADEBUG) -- arla: controls arla debug;
1678 * 62 (VIOC_AVIATOR) -- arla: debug interface;
1679 * 63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status;
1680 * 64 (VIOC_CALCULATE_CACHE) -- arla: force cache check;
1681 * 65 (VIOC_BREAKCELLBACK) -- arla: break callback;
1682 * 68 (?) -- arla: fetch stats;
1686 AFS_STATCNT(PBogus
);
1691 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
1695 * \param[in] ain not in use (avc used to pass in file id)
1696 * \param[out] aout cell name
1698 * \retval EINVAL Error if some of the standard args aren't set
1699 * \retval ESRCH Error if the file isn't part of a cell
1701 * \post Get a cell based on a passed in file id
1703 DECL_PIOCTL(PGetFileCell
)
1707 AFS_STATCNT(PGetFileCell
);
1710 tcell
= afs_GetCell(avc
->f
.fid
.Cell
, READ_LOCK
);
1714 if (afs_pd_putString(aout
, tcell
->cellName
) != 0)
1717 afs_PutCell(tcell
, READ_LOCK
);
1722 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
1726 * \param[in] ain not in use
1727 * \param[out] aout cell name
1730 * Error if the afs daemon hasn't started yet
1732 * Error if the machine isn't part of a cell, for whatever reason
1734 * \post Get the primary cell that the machine is a part of.
1736 DECL_PIOCTL(PGetWSCell
)
1738 struct cell
*tcell
= NULL
;
1740 AFS_STATCNT(PGetWSCell
);
1741 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
1742 return EIO
; /* Inappropriate ioctl for device */
1744 tcell
= afs_GetPrimaryCell(READ_LOCK
);
1745 if (!tcell
) /* no primary cell? */
1748 if (afs_pd_putString(aout
, tcell
->cellName
) != 0)
1750 afs_PutCell(tcell
, READ_LOCK
);
1755 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
1759 * \param[in] ain not in use (user id found via areq)
1760 * \param[out] aout cell name
1763 * Error if the user id doesn't have a primary cell specified
1765 * \post Get the primary cell for a certain user, based on the user's uid
1767 DECL_PIOCTL(PGetUserCell
)
1770 struct unixuser
*tu
;
1773 AFS_STATCNT(PGetUserCell
);
1774 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
1775 return EIO
; /* Inappropriate ioctl for device */
1777 /* return the cell name of the primary cell for this user */
1778 i
= UHash(areq
->uid
);
1779 ObtainWriteLock(&afs_xuser
, 224);
1780 for (tu
= afs_users
[i
]; tu
; tu
= tu
->next
) {
1781 if (tu
->uid
== areq
->uid
&& (tu
->states
& UPrimary
)) {
1783 ReleaseWriteLock(&afs_xuser
);
1784 afs_LockUser(tu
, READ_LOCK
, 0);
1789 tcell
= afs_GetCell(tu
->cell
, READ_LOCK
);
1790 afs_PutUser(tu
, READ_LOCK
);
1794 if (afs_pd_putString(aout
, tcell
->cellName
) != 0)
1796 afs_PutCell(tcell
, READ_LOCK
);
1799 ReleaseWriteLock(&afs_xuser
);
1804 /* Work out which cell we're changing tokens for */
1806 _settok_tokenCell(char *cellName
, int *cellNum
, int *primary
) {
1814 if (cellName
&& strlen(cellName
) > 0) {
1815 cell
= afs_GetCellByName(cellName
, READ_LOCK
);
1817 cell
= afs_GetPrimaryCell(READ_LOCK
);
1828 *cellNum
= cell
->cellNum
;
1829 afs_PutCell(cell
, READ_LOCK
);
1836 _settok_setParentPag(afs_ucred_t
**cred
) {
1838 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1840 osi_procname(procname
, 256);
1841 afs_warnuser("Process %d (%s) tried to change pags in PSetTokens\n",
1842 MyPidxx2Pid(MyPidxx
), procname
);
1843 return setpag(osi_curproc(), cred
, -1, &pag
, 1);
1845 return setpag(cred
, -1, &pag
, 1);
1850 * VIOCSETTOK (3) - Set authentication tokens
1854 * \param[in] ain the krb tickets from which to set the afs tokens
1855 * \param[out] aout not in use
1858 * Error if the ticket is either too long or too short
1860 * Error if the AFS initState is below 101
1862 * Error if the cell for which the Token is being set can't be found
1865 * Set the Tokens for a specific cell name, unless there is none set,
1866 * then default to primary
1869 DECL_PIOCTL(PSetTokens
)
1874 struct unixuser
*tu
;
1875 struct ClearToken clear
;
1879 struct vrequest
*treq
= NULL
;
1880 afs_int32 flag
, set_parent_pag
= 0;
1882 AFS_STATCNT(PSetTokens
);
1883 if (!afs_resourceinit_flag
) {
1887 if (afs_pd_getInt(ain
, &stLen
) != 0)
1890 stp
= afs_pd_where(ain
); /* remember where the ticket is */
1891 if (stLen
< 0 || stLen
> MAXKTCTICKETLEN
)
1892 return EINVAL
; /* malloc may fail */
1893 if (afs_pd_skip(ain
, stLen
) != 0)
1896 if (afs_pd_getInt(ain
, &size
) != 0)
1898 if (size
!= sizeof(struct ClearToken
))
1901 if (afs_pd_getBytes(ain
, &clear
, sizeof(struct ClearToken
)) !=0)
1904 if (clear
.AuthHandle
== -1)
1905 clear
.AuthHandle
= 999; /* more rxvab compat stuff */
1907 if (afs_pd_remaining(ain
) != 0) {
1908 /* still stuff left? we've got primary flag and cell name.
1911 if (afs_pd_getInt(ain
, &flag
) != 0)
1914 /* some versions of gcc appear to need != 0 in order to get this
1916 if ((flag
& 0x8000) != 0) { /* XXX Use Constant XXX */
1921 if (afs_pd_getStringPtr(ain
, &cellName
) != 0)
1924 code
= _settok_tokenCell(cellName
, &cellNum
, NULL
);
1928 /* default to primary cell, primary id */
1929 code
= _settok_tokenCell(NULL
, &cellNum
, &flag
);
1934 if (set_parent_pag
) {
1935 if (_settok_setParentPag(acred
) == 0) {
1936 code
= afs_CreateReq(&treq
, *acred
);
1944 /* now we just set the tokens */
1945 tu
= afs_GetUser(areq
->uid
, cellNum
, WRITE_LOCK
);
1946 /* Set tokens destroys any that are already there */
1947 afs_FreeTokens(&tu
->tokens
);
1948 afs_AddRxkadToken(&tu
->tokens
, stp
, stLen
, &clear
);
1950 afs_stats_cmfullperf
.authent
.TicketUpdates
++;
1951 afs_ComputePAGStats();
1952 #endif /* AFS_NOSTATS */
1953 tu
->states
|= UHasTokens
;
1954 tu
->states
&= ~UTokensBad
;
1955 afs_SetPrimary(tu
, flag
);
1956 tu
->tokenTime
= osi_Time();
1957 afs_ResetUserConns(tu
);
1958 afs_NotifyUser(tu
, UTokensObtained
);
1959 afs_PutUser(tu
, WRITE_LOCK
);
1960 afs_DestroyReq(treq
);
1966 * VIOCGETVOLSTAT (4) - Get volume status
1970 * \param[in] ain not in use
1971 * \param[out] aout status of the volume
1973 * \retval EINVAL Error if some of the standard args aren't set
1976 * The status of a volume (based on the FID of the volume), or an
1977 * offline message /motd
1979 DECL_PIOCTL(PGetVolumeStatus
)
1982 char *offLineMsg
= afs_osi_Alloc(256);
1983 char *motd
= afs_osi_Alloc(256);
1984 struct afs_conn
*tc
;
1986 struct AFSFetchVolumeStatus volstat
;
1988 struct rx_connection
*rxconn
;
1991 osi_Assert(offLineMsg
!= NULL
);
1992 osi_Assert(motd
!= NULL
);
1993 AFS_STATCNT(PGetVolumeStatus
);
2000 tc
= afs_Conn(&avc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
2002 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS
);
2005 RXAFS_GetVolumeStatus(rxconn
, avc
->f
.fid
.Fid
.Volume
, &volstat
,
2006 &Name
, &offLineMsg
, &motd
);
2011 } while (afs_Analyze
2012 (tc
, rxconn
, code
, &avc
->f
.fid
, areq
, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS
,
2013 SHARED_LOCK
, NULL
));
2017 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
2018 if (afs_pd_putBytes(aout
, &volstat
, sizeof(VolumeStatus
)) != 0)
2020 if (afs_pd_putString(aout
, volName
) != 0)
2022 if (afs_pd_putString(aout
, offLineMsg
) != 0)
2024 if (afs_pd_putString(aout
, motd
) != 0)
2027 afs_osi_Free(offLineMsg
, 256);
2028 afs_osi_Free(motd
, 256);
2033 * VIOCSETVOLSTAT (5) - Set volume status
2038 * values to set the status at, offline message, message of the day,
2039 * volume name, minimum quota, maximum quota
2041 * status of a volume, offlines messages, minimum quota, maximumm quota
2044 * Error if some of the standard args aren't set
2046 * Error if the volume is read only, or a backup volume
2048 * Error if the volume can't be accessed
2050 * Error if the volume name, offline message, and motd are too big
2053 * Set the status of a volume, including any offline messages,
2054 * a minimum quota, and a maximum quota
2056 DECL_PIOCTL(PSetVolumeStatus
)
2061 struct afs_conn
*tc
;
2063 struct AFSFetchVolumeStatus volstat
;
2064 struct AFSStoreVolumeStatus storeStat
;
2066 struct rx_connection
*rxconn
;
2069 AFS_STATCNT(PSetVolumeStatus
);
2072 memset(&storeStat
, 0, sizeof(storeStat
));
2074 tvp
= afs_GetVolume(&avc
->f
.fid
, areq
, READ_LOCK
);
2076 if (tvp
->states
& (VRO
| VBackup
)) {
2077 afs_PutVolume(tvp
, READ_LOCK
);
2080 afs_PutVolume(tvp
, READ_LOCK
);
2085 if (afs_pd_getBytes(ain
, &volstat
, sizeof(AFSFetchVolumeStatus
)) != 0)
2088 if (afs_pd_getStringPtr(ain
, &volName
) != 0)
2090 if (strlen(volName
) > 32)
2093 if (afs_pd_getStringPtr(ain
, &offLineMsg
) != 0)
2095 if (strlen(offLineMsg
) > 256)
2098 if (afs_pd_getStringPtr(ain
, &motd
) != 0)
2100 if (strlen(motd
) > 256)
2103 /* Done reading ... */
2106 if (volstat
.MinQuota
!= -1) {
2107 storeStat
.MinQuota
= volstat
.MinQuota
;
2108 storeStat
.Mask
|= AFS_SETMINQUOTA
;
2110 if (volstat
.MaxQuota
!= -1) {
2111 storeStat
.MaxQuota
= volstat
.MaxQuota
;
2112 storeStat
.Mask
|= AFS_SETMAXQUOTA
;
2115 tc
= afs_Conn(&avc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
2117 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS
);
2120 RXAFS_SetVolumeStatus(rxconn
, avc
->f
.fid
.Fid
.Volume
, &storeStat
,
2121 volName
, offLineMsg
, motd
);
2126 } while (afs_Analyze
2127 (tc
, rxconn
, code
, &avc
->f
.fid
, areq
, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS
,
2128 SHARED_LOCK
, NULL
));
2132 /* we are sending parms back to make compat. with prev system. should
2133 * change interface later to not ask for current status, just set new
2136 if (afs_pd_putBytes(aout
, &volstat
, sizeof(VolumeStatus
)) != 0)
2138 if (afs_pd_putString(aout
, volName
) != 0)
2140 if (afs_pd_putString(aout
, offLineMsg
) != 0)
2142 if (afs_pd_putString(aout
, motd
) != 0)
2149 * VIOCFLUSH (6) - Invalidate cache entry
2153 * \param[in] ain not in use
2154 * \param[out] aout not in use
2156 * \retval EINVAL Error if some of the standard args aren't set
2158 * \post Flush any information the cache manager has on an entry
2162 AFS_STATCNT(PFlush
);
2165 ObtainWriteLock(&avc
->lock
, 225);
2166 afs_ResetVCache(avc
, *acred
, 0);
2167 ReleaseWriteLock(&avc
->lock
);
2172 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
2177 * the last component in a path, related to mountpoint that we're
2178 * looking for information about
2180 * volume, cell, link data
2182 * \retval EINVAL Error if some of the standard args aren't set
2183 * \retval ENOTDIR Error if the 'mount point' argument isn't a directory
2184 * \retval EIO Error if the link data can't be accessed
2186 * \post Get the volume, and cell, as well as the link data for a mount point
2188 DECL_PIOCTL(PNewStatMount
)
2193 struct VenusFid tfid
;
2196 struct sysname_info sysState
;
2197 afs_size_t offset
, len
;
2199 AFS_STATCNT(PNewStatMount
);
2203 if (afs_pd_getStringPtr(ain
, &name
) != 0)
2206 code
= afs_VerifyVCache(avc
, areq
);
2209 if (vType(avc
) != VDIR
) {
2212 tdc
= afs_GetDCache(avc
, (afs_size_t
) 0, areq
, &offset
, &len
, 1);
2215 Check_AtSys(avc
, name
, &sysState
, areq
);
2216 ObtainReadLock(&tdc
->lock
);
2218 code
= afs_dir_Lookup(tdc
, sysState
.name
, &tfid
.Fid
);
2219 } while (code
== ENOENT
&& Next_AtSys(avc
, areq
, &sysState
));
2220 ReleaseReadLock(&tdc
->lock
);
2221 afs_PutDCache(tdc
); /* we're done with the data */
2222 bufp
= sysState
.name
;
2226 tfid
.Cell
= avc
->f
.fid
.Cell
;
2227 tfid
.Fid
.Volume
= avc
->f
.fid
.Fid
.Volume
;
2228 if (!tfid
.Fid
.Unique
&& (avc
->f
.states
& CForeign
)) {
2229 tvc
= afs_LookupVCache(&tfid
, areq
, NULL
, avc
, bufp
);
2231 tvc
= afs_GetVCache(&tfid
, areq
, NULL
, NULL
);
2237 if (tvc
->mvstat
!= AFS_MVSTAT_MTPT
) {
2242 ObtainWriteLock(&tvc
->lock
, 226);
2243 code
= afs_HandleLink(tvc
, areq
);
2245 if (tvc
->linkData
) {
2246 if ((tvc
->linkData
[0] != '#') && (tvc
->linkData
[0] != '%'))
2249 /* we have the data */
2250 if (afs_pd_putString(aout
, tvc
->linkData
) != 0)
2256 ReleaseWriteLock(&tvc
->lock
);
2259 if (sysState
.allocked
)
2260 osi_FreeLargeSpace(bufp
);
2265 * A helper function to get the n'th cell which a particular user has tokens
2266 * for. This is racy. If new tokens are added whilst we're iterating, then
2267 * we may return some cells twice. If tokens expire mid run, then we'll
2268 * miss some cells from our output. So, could be better, but that would
2269 * require an interface change.
2272 static struct unixuser
*
2273 getNthCell(afs_int32 uid
, afs_int32 iterator
) {
2275 struct unixuser
*tu
= NULL
;
2278 ObtainReadLock(&afs_xuser
);
2279 for (tu
= afs_users
[i
]; tu
; tu
= tu
->next
) {
2280 if (tu
->uid
== uid
&& (tu
->states
& UHasTokens
)) {
2281 if (iterator
-- == 0)
2282 break; /* are we done yet? */
2288 ReleaseReadLock(&afs_xuser
);
2290 afs_LockUser(tu
, READ_LOCK
, 0);
2297 * VIOCGETTOK (8) - Get authentication tokens
2301 * \param[in] ain cellid to return tokens for
2302 * \param[out] aout token
2305 * Error if the afs daemon hasn't started yet
2307 * Error if the input parameter is out of the bounds of the available
2310 * Error if there aren't tokens for this cell
2313 * If the input paramater exists, get the token that corresponds to
2314 * the parameter value, if there is no token at this value, get the
2315 * token for the first cell
2317 * \notes "it's a weird interface (from comments in the code)"
2320 DECL_PIOCTL(PGetTokens
)
2323 struct unixuser
*tu
= NULL
;
2324 union tokenUnion
*token
;
2325 afs_int32 iterator
= 0;
2330 AFS_STATCNT(PGetTokens
);
2331 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2332 return EIO
; /* Inappropriate ioctl for device */
2334 /* weird interface. If input parameter is present, it is an integer and
2335 * we're supposed to return the parm'th tokens for this unix uid.
2336 * If not present, we just return tokens for cell 1.
2337 * If counter out of bounds, return EDOM.
2338 * If no tokens for the particular cell, return ENOTCONN.
2339 * Also, if this mysterious parm is present, we return, along with the
2340 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
2341 * at the end, in that order.
2343 newStyle
= (afs_pd_remaining(ain
) > 0);
2345 if (afs_pd_getInt(ain
, &iterator
) != 0)
2349 tu
= getNthCell(areq
->uid
, iterator
);
2351 cellNum
= afs_GetPrimaryCellNum();
2353 tu
= afs_FindUser(areq
->uid
, cellNum
, READ_LOCK
);
2358 if (!(tu
->states
& UHasTokens
)
2359 || !afs_HasUsableTokens(tu
->tokens
, osi_Time())) {
2360 tu
->states
|= (UTokensBad
| UNeedsReset
);
2361 afs_NotifyUser(tu
, UTokensDropped
);
2362 afs_PutUser(tu
, READ_LOCK
);
2365 token
= afs_FindToken(tu
->tokens
, RX_SECIDX_KAD
);
2367 /* If they don't have an RXKAD token, but do have other tokens,
2368 * then sadly there's nothing this interface can do to help them. */
2372 /* for compat, we try to return 56 byte tix if they fit */
2373 iterator
= token
->rxkad
.ticketLen
;
2375 iterator
= 56; /* # of bytes we're returning */
2377 if (afs_pd_putInt(aout
, iterator
) != 0)
2379 if (afs_pd_putBytes(aout
, token
->rxkad
.ticket
, token
->rxkad
.ticketLen
) != 0)
2381 if (token
->rxkad
.ticketLen
< 56) {
2382 /* Tokens are always 56 bytes or larger */
2383 if (afs_pd_skip(aout
, iterator
- token
->rxkad
.ticketLen
) != 0) {
2388 if (afs_pd_putInt(aout
, sizeof(struct ClearToken
)) != 0)
2390 if (afs_pd_putBytes(aout
, &token
->rxkad
.clearToken
,
2391 sizeof(struct ClearToken
)) != 0)
2395 /* put out primary id and cell name, too */
2396 iterator
= (tu
->states
& UPrimary
? 1 : 0);
2397 if (afs_pd_putInt(aout
, iterator
) != 0)
2399 tcell
= afs_GetCell(tu
->cell
, READ_LOCK
);
2401 if (afs_pd_putString(aout
, tcell
->cellName
) != 0)
2403 afs_PutCell(tcell
, READ_LOCK
);
2405 if (afs_pd_putString(aout
, "") != 0)
2408 /* Got here, all is good */
2411 afs_PutUser(tu
, READ_LOCK
);
2416 * VIOCUNLOG (9) - Invalidate tokens
2420 * \param[in] ain not in use
2421 * \param[out] aout not in use
2423 * \retval EIO Error if the afs daemon hasn't been started yet
2425 * \post remove tokens from a user, specified by the user id
2427 * \notes sets the token's time to 0, which then causes it to be removed
2428 * \notes Unlog is the same as un-pag in OpenAFS
2433 struct unixuser
*tu
;
2435 AFS_STATCNT(PUnlog
);
2436 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2437 return EIO
; /* Inappropriate ioctl for device */
2439 i
= UHash(areq
->uid
);
2440 ObtainWriteLock(&afs_xuser
, 227);
2441 for (tu
= afs_users
[i
]; tu
; tu
= tu
->next
) {
2442 if (tu
->uid
== areq
->uid
) {
2444 ReleaseWriteLock(&afs_xuser
);
2446 afs_LockUser(tu
, WRITE_LOCK
, 366);
2448 tu
->states
&= ~UHasTokens
;
2449 afs_FreeTokens(&tu
->tokens
);
2450 afs_NotifyUser(tu
, UTokensDropped
);
2451 /* We have to drop the lock over the call to afs_ResetUserConns,
2452 * since it obtains the afs_xvcache lock. We could also keep
2453 * the lock, and modify ResetUserConns to take parm saying we
2454 * obtained the lock already, but that is overkill. By keeping
2455 * the "tu" pointer held over the released lock, we guarantee
2456 * that we won't lose our place, and that we'll pass over
2457 * every user conn that existed when we began this call.
2459 afs_ResetUserConns(tu
);
2460 afs_PutUser(tu
, WRITE_LOCK
);
2461 ObtainWriteLock(&afs_xuser
, 228);
2463 /* set the expire times to 0, causes
2464 * afs_GCUserData to remove this entry
2467 #endif /* UKERNEL */
2470 ReleaseWriteLock(&afs_xuser
);
2475 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2479 * \param[in] ain host address to be set
2480 * \param[out] aout old host address
2483 * depending on whether or not a variable is set, either get the host
2484 * for the cache manager monitor, or set the old address and give it
2487 * \notes Errors turn off mariner
2489 DECL_PIOCTL(PMariner
)
2491 afs_int32 newHostAddr
;
2492 afs_int32 oldHostAddr
;
2494 AFS_STATCNT(PMariner
);
2496 memcpy((char *)&oldHostAddr
, (char *)&afs_marinerHost
,
2499 oldHostAddr
= 0xffffffff; /* disabled */
2501 if (afs_pd_getInt(ain
, &newHostAddr
) != 0)
2504 if (newHostAddr
== 0xffffffff) {
2505 /* disable mariner operations */
2507 } else if (newHostAddr
) {
2509 afs_marinerHost
= newHostAddr
;
2512 if (afs_pd_putInt(aout
, oldHostAddr
) != 0)
2519 * VIOCCKSERV (10) - Check that servers are up
2523 * \param[in] ain name of the cell
2524 * \param[out] aout current down server list
2526 * \retval EIO Error if the afs daemon hasn't started yet
2527 * \retval EACCES Error if the user doesn't have super-user credentials
2528 * \retval ENOENT Error if we are unable to obtain the cell
2531 * Either a fast check (where it doesn't contact servers) or a
2532 * local check (checks local cell only)
2534 DECL_PIOCTL(PCheckServers
)
2539 char *cellName
= NULL
;
2541 struct chservinfo
*pcheck
;
2543 AFS_STATCNT(PCheckServers
);
2545 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2546 return EIO
; /* Inappropriate ioctl for device */
2548 /* This is tricky, because we need to peak at the datastream to see
2549 * what we're getting. For now, let's cheat. */
2551 /* ain contains either an int32 or a string */
2552 if (ain
->remaining
== 0)
2555 if (*(afs_int32
*)ain
->ptr
== 0x12345678) { /* For afs3.3 version */
2556 pcheck
= afs_pd_inline(ain
, sizeof(*pcheck
));
2560 if (pcheck
->tinterval
>= 0) {
2561 if (afs_pd_putInt(aout
, afs_probe_interval
) != 0)
2563 if (pcheck
->tinterval
> 0) {
2564 if (!afs_osi_suser(*acred
))
2566 afs_probe_interval
= pcheck
->tinterval
;
2570 temp
= pcheck
->tflags
;
2572 cellName
= pcheck
->tbuffer
;
2573 } else { /* For pre afs3.3 versions */
2574 if (afs_pd_getInt(ain
, &temp
) != 0)
2576 if (afs_pd_remaining(ain
) > 0) {
2577 if (afs_pd_getStringPtr(ain
, &cellName
) != 0)
2583 * 1: fast check, don't contact servers.
2584 * 2: local cell only.
2587 /* have cell name, too */
2588 cellp
= afs_GetCellByName(cellName
, READ_LOCK
);
2593 if (!cellp
&& (temp
& 2)) {
2594 /* use local cell */
2595 cellp
= afs_GetPrimaryCell(READ_LOCK
);
2597 if (!(temp
& 1)) { /* if not fast, call server checker routine */
2598 afs_CheckServers(1, cellp
); /* check down servers */
2599 afs_CheckServers(0, cellp
); /* check up servers */
2601 /* now return the current down server list */
2602 ObtainReadLock(&afs_xserver
);
2603 for (i
= 0; i
< NSERVERS
; i
++) {
2604 for (ts
= afs_servers
[i
]; ts
; ts
= ts
->next
) {
2605 if (cellp
&& ts
->cell
!= cellp
)
2606 continue; /* cell spec'd and wrong */
2607 if ((ts
->flags
& SRVR_ISDOWN
)
2608 && ts
->addr
->sa_portal
!= ts
->cell
->vlport
) {
2609 afs_pd_putInt(aout
, ts
->addr
->sa_ip
);
2613 ReleaseReadLock(&afs_xserver
);
2615 afs_PutCell(cellp
, READ_LOCK
);
2620 * VIOCCKBACK (11) - Check backup volume mappings
2624 * \param[in] ain not in use
2625 * \param[out] aout not in use
2627 * \retval EIO Error if the afs daemon hasn't started yet
2630 * Check the root volume, and then check the names if the volume
2631 * check variable is set to force, has expired, is busy, or if
2632 * the mount points variable is set
2634 DECL_PIOCTL(PCheckVolNames
)
2636 AFS_STATCNT(PCheckVolNames
);
2637 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2638 return EIO
; /* Inappropriate ioctl for device */
2640 afs_CheckRootVolume();
2641 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE
| AFS_VOLCHECK_EXPIRED
|
2642 AFS_VOLCHECK_BUSY
| AFS_VOLCHECK_MTPTS
);
2647 * VIOCCKCONN (12) - Check connections for a user
2651 * \param[in] ain not in use
2652 * \param[out] aout not in use
2655 * Error if no user is specififed, the user has no tokens set,
2656 * or if the user's tokens are bad
2659 * check to see if a user has the correct authentication.
2660 * If so, allow access.
2662 * \notes Check the connections to all the servers specified
2664 DECL_PIOCTL(PCheckAuth
)
2668 struct sa_conn_vector
*tcv
;
2669 struct unixuser
*tu
;
2672 AFS_STATCNT(PCheckAuth
);
2673 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2674 return EIO
; /* Inappropriate ioctl for device */
2677 tu
= afs_GetUser(areq
->uid
, 1, READ_LOCK
); /* check local cell authentication */
2681 /* we have a user */
2682 ObtainReadLock(&afs_xsrvAddr
);
2683 ObtainReadLock(&afs_xconn
);
2685 /* any tokens set? */
2686 if ((tu
->states
& UHasTokens
) == 0)
2688 /* all connections in cell 1 working? */
2689 for (i
= 0; i
< NSERVERS
; i
++) {
2690 for (sa
= afs_srvAddrs
[i
]; sa
; sa
= sa
->next_bkt
) {
2691 for (tcv
= sa
->conns
; tcv
; tcv
= tcv
->next
) {
2692 if (tcv
->user
== tu
&& (tu
->states
& UTokensBad
))
2697 ReleaseReadLock(&afs_xsrvAddr
);
2698 ReleaseReadLock(&afs_xconn
);
2699 afs_PutUser(tu
, READ_LOCK
);
2701 if (afs_pd_putInt(aout
, retValue
) != 0)
2707 Prefetch(uparmtype apath
, struct afs_ioctl
*adata
, int afollow
,
2712 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2718 AFS_STATCNT(Prefetch
);
2721 tp
= osi_AllocLargeSpace(1024);
2722 AFS_COPYINSTR(apath
, tp
, 1024, &bufferSize
, code
);
2724 osi_FreeLargeSpace(tp
);
2727 if (afs_BBusy()) { /* do this as late as possible */
2728 osi_FreeLargeSpace(tp
);
2729 return EWOULDBLOCK
; /* pretty close */
2731 afs_BQueue(BOP_PATH
, (struct vcache
*)0, 0, 0, acred
, (afs_size_t
) 0,
2732 (afs_size_t
) 0, tp
, (void *)0, (void *)0);
2737 * VIOCWHEREIS (14) - Find out where a volume is located
2741 * \param[in] ain not in use
2742 * \param[out] aout volume location
2744 * \retval EINVAL Error if some of the default arguments don't exist
2745 * \retval ENODEV Error if there is no such volume
2747 * \post fine a volume, based on a volume file id
2749 * \notes check each of the servers specified
2751 DECL_PIOCTL(PFindVolume
)
2758 AFS_STATCNT(PFindVolume
);
2761 tvp
= afs_GetVolume(&avc
->f
.fid
, areq
, READ_LOCK
);
2765 for (i
= 0; i
< AFS_MAXHOSTS
; i
++) {
2766 ts
= tvp
->serverHost
[i
];
2769 if (afs_pd_putInt(aout
, ts
->addr
->sa_ip
) != 0) {
2774 if (i
< AFS_MAXHOSTS
) {
2775 /* still room for terminating NULL, add it on */
2776 if (afs_pd_putInt(aout
, 0) != 0) {
2782 afs_PutVolume(tvp
, READ_LOCK
);
2787 * VIOCACCESS (20) - Access using PRS_FS bits
2791 * \param[in] ain PRS_FS bits
2792 * \param[out] aout not in use
2794 * \retval EINVAL Error if some of the initial arguments aren't set
2795 * \retval EACCES Error if access is denied
2797 * \post check to make sure access is allowed
2799 DECL_PIOCTL(PViceAccess
)
2804 AFS_STATCNT(PViceAccess
);
2808 code
= afs_VerifyVCache(avc
, areq
);
2812 if (afs_pd_getInt(ain
, &temp
) != 0)
2815 code
= afs_AccessOK(avc
, temp
, areq
, CHECK_MODE_BITS
);
2823 * VIOC_GETPAG (13) - Get PAG value
2827 * \param[in] ain not in use
2828 * \param[out] aout PAG value or NOPAG
2830 * \post get PAG value for the caller's cred
2832 DECL_PIOCTL(PGetPAG
)
2836 pag
= PagInCred(*acred
);
2838 return afs_pd_putInt(aout
, pag
);
2841 DECL_PIOCTL(PPrecache
)
2845 /*AFS_STATCNT(PPrecache);*/
2846 if (!afs_osi_suser(*acred
))
2849 if (afs_pd_getInt(ain
, &newValue
) != 0)
2852 afs_preCache
= newValue
*1024;
2857 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2861 * \param[in] ain the size the venus cache should be set to
2862 * \param[out] aout not in use
2864 * \retval EACCES Error if the user doesn't have super-user credentials
2865 * \retval EROFS Error if the cache is set to be in memory
2868 * Set the cache size based on user input. If no size is given,
2869 * set it to the default OpenAFS cache size.
2872 * recompute the general cache parameters for every single block allocated
2874 DECL_PIOCTL(PSetCacheSize
)
2879 AFS_STATCNT(PSetCacheSize
);
2881 if (!afs_osi_suser(*acred
))
2883 /* too many things are setup initially in mem cache version */
2884 if (cacheDiskType
== AFS_FCACHE_TYPE_MEM
)
2886 if (afs_pd_getInt(ain
, &newValue
) != 0)
2889 afs_cacheBlocks
= afs_stats_cmperf
.cacheBlocksOrig
;
2891 if (newValue
< afs_min_cache
)
2892 afs_cacheBlocks
= afs_min_cache
;
2894 afs_cacheBlocks
= newValue
;
2896 afs_stats_cmperf
.cacheBlocksTotal
= afs_cacheBlocks
;
2897 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2898 afs_MaybeWakeupTruncateDaemon();
2899 while (waitcnt
++ < 100 && afs_cacheBlocks
< afs_blocksUsed
) {
2900 afs_osi_Wait(1000, 0, 0);
2901 afs_MaybeWakeupTruncateDaemon();
2906 #define MAXGCSTATS 16
2908 * VIOCGETCACHEPARMS (40) - Get cache stats
2912 * \param[in] ain afs index flags
2913 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2915 * \post Get the cache blocks, and how many of the cache blocks there are
2917 DECL_PIOCTL(PGetCacheSize
)
2919 afs_int32 results
[MAXGCSTATS
];
2921 struct dcache
* tdc
;
2924 AFS_STATCNT(PGetCacheSize
);
2926 if (afs_pd_remaining(ain
) == sizeof(afs_int32
)) {
2927 afs_pd_getInt(ain
, &flags
); /* can't error, we just checked size */
2928 } else if (afs_pd_remaining(ain
) == 0) {
2934 memset(results
, 0, sizeof(results
));
2935 results
[0] = afs_cacheBlocks
;
2936 results
[1] = afs_blocksUsed
;
2937 results
[2] = afs_cacheFiles
;
2940 for (i
= 0; i
< afs_cacheFiles
; i
++) {
2941 if (afs_indexFlags
[i
] & IFFree
) results
[3]++;
2943 } else if (2 == flags
){
2944 for (i
= 0; i
< afs_cacheFiles
; i
++) {
2945 if (afs_indexFlags
[i
] & IFFree
) results
[3]++;
2946 if (afs_indexFlags
[i
] & IFEverUsed
) results
[4]++;
2947 if (afs_indexFlags
[i
] & IFDataMod
) results
[5]++;
2948 if (afs_indexFlags
[i
] & IFDirtyPages
) results
[6]++;
2949 if (afs_indexFlags
[i
] & IFAnyPages
) results
[7]++;
2950 if (afs_indexFlags
[i
] & IFDiscarded
) results
[8]++;
2952 tdc
= afs_indexTable
[i
];
2954 afs_size_t size
= tdc
->validPos
;
2957 if ( 0 <= size
&& size
< (1<<12) ) results
[10]++;
2958 else if (size
< (1<<14) ) results
[11]++;
2959 else if (size
< (1<<16) ) results
[12]++;
2960 else if (size
< (1<<18) ) results
[13]++;
2961 else if (size
< (1<<20) ) results
[14]++;
2962 else if (size
>= (1<<20) ) results
[15]++;
2966 return afs_pd_putBytes(aout
, results
, sizeof(results
));
2970 * VIOCFLUSHCB (25) - Flush callback only
2974 * \param[in] ain not in use
2975 * \param[out] aout not in use
2977 * \retval EINVAL Error if some of the standard args aren't set
2978 * \retval 0 0 returned if the volume is set to read-only
2981 * Flushes callbacks, by setting the length of callbacks to one,
2982 * setting the next callback to be sent to the CB_DROPPED value,
2983 * and then dequeues everything else.
2985 DECL_PIOCTL(PRemoveCallBack
)
2987 struct afs_conn
*tc
;
2989 struct AFSCallBack CallBacks_Array
[1];
2990 struct AFSCBFids theFids
;
2991 struct AFSCBs theCBs
;
2992 struct rx_connection
*rxconn
;
2995 AFS_STATCNT(PRemoveCallBack
);
2998 if (avc
->f
.states
& CRO
)
2999 return 0; /* read-only-ness can't change */
3000 ObtainWriteLock(&avc
->lock
, 229);
3001 theFids
.AFSCBFids_len
= 1;
3002 theCBs
.AFSCBs_len
= 1;
3003 theFids
.AFSCBFids_val
= (struct AFSFid
*)&avc
->f
.fid
.Fid
;
3004 theCBs
.AFSCBs_val
= CallBacks_Array
;
3005 CallBacks_Array
[0].CallBackType
= CB_DROPPED
;
3006 if (avc
->callback
) {
3008 tc
= afs_Conn(&avc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
3010 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS
);
3012 code
= RXAFS_GiveUpCallBacks(rxconn
, &theFids
, &theCBs
);
3016 /* don't set code on failure since we wouldn't use it */
3017 } while (afs_Analyze
3018 (tc
, rxconn
, code
, &avc
->f
.fid
, areq
,
3019 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS
, SHARED_LOCK
, NULL
));
3021 afs_StaleVCacheFlags(avc
, AFS_STALEVC_CLEARCB
, CUnique
);
3023 ReleaseWriteLock(&avc
->lock
);
3028 * VIOCNEWCELL (26) - Configure new cell
3033 * the name of the cell, the hosts that will be a part of the cell,
3034 * whether or not it's linked with another cell, the other cell it's
3035 * linked with, the file server port, and the volume server port
3039 * \retval EIO Error if the afs daemon hasn't started yet
3040 * \retval EACCES Error if the user doesn't have super-user cedentials
3041 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
3043 * \post creates a new cell
3045 DECL_PIOCTL(PNewCell
)
3047 afs_int32 cellHosts
[AFS_MAXCELLHOSTS
], magic
= 0;
3048 char *newcell
= NULL
;
3049 char *linkedcell
= NULL
;
3051 afs_int32 linkedstate
= 0;
3052 afs_int32 fsport
= 0, vlport
= 0;
3055 AFS_STATCNT(PNewCell
);
3056 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3057 return EIO
; /* Inappropriate ioctl for device */
3059 if (!afs_osi_suser(*acred
))
3062 if (afs_pd_getInt(ain
, &magic
) != 0)
3064 if (magic
!= 0x12345678)
3067 /* A 3.4 fs newcell command will pass an array of AFS_MAXCELLHOSTS
3068 * server addresses while the 3.5 fs newcell command passes
3069 * AFS_MAXHOSTS. To figure out which is which, check if the cellname
3072 * This whole logic is bogus, because it relies on the newer command
3073 * sending its 12th address as 0.
3075 if (afs_pd_remaining(ain
) < (AFS_MAXCELLHOSTS
+ 3) * sizeof(afs_int32
))
3078 newcell
= afs_pd_where(ain
) + (AFS_MAXCELLHOSTS
+ 3) * sizeof(afs_int32
);
3079 if (newcell
[0] != '\0') {
3082 skip
= AFS_MAXHOSTS
- AFS_MAXCELLHOSTS
;
3085 /* AFS_MAXCELLHOSTS (=8) is less than AFS_MAXHOSTS (=13) */
3086 if (afs_pd_getBytes(ain
, &cellHosts
,
3087 AFS_MAXCELLHOSTS
* sizeof(afs_int32
)) != 0)
3089 if (afs_pd_skip(ain
, skip
* sizeof(afs_int32
)) !=0)
3092 if (afs_pd_getInt(ain
, &fsport
) != 0)
3095 fsport
= 0; /* Privileged ports not allowed */
3097 if (afs_pd_getInt(ain
, &vlport
) != 0)
3100 vlport
= 0; /* Privileged ports not allowed */
3102 if (afs_pd_getInt(ain
, &ls
) != 0)
3105 if (afs_pd_getStringPtr(ain
, &newcell
) != 0)
3109 if (afs_pd_getStringPtr(ain
, &linkedcell
) != 0)
3111 linkedstate
|= CLinkedCell
;
3114 linkedstate
|= CNoSUID
; /* setuid is disabled by default for fs newcell */
3116 afs_NewCell(newcell
, cellHosts
, linkedstate
, linkedcell
, fsport
,
3121 DECL_PIOCTL(PNewAlias
)
3123 /* create a new cell alias */
3124 char *realName
, *aliasName
;
3126 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3127 return EIO
; /* Inappropriate ioctl for device */
3129 if (!afs_osi_suser(*acred
))
3132 if (afs_pd_getStringPtr(ain
, &aliasName
) != 0)
3134 if (afs_pd_getStringPtr(ain
, &realName
) != 0)
3137 return afs_NewCellAlias(aliasName
, realName
);
3141 * VIOCGETCELL (27) - Get cell info
3145 * \param[in] ain The cell index of a specific cell
3146 * \param[out] aout list of servers in the cell
3148 * \retval EIO Error if the afs daemon hasn't started yet
3149 * \retval EDOM Error if there is no cell asked about
3151 * \post Lists the cell's server names and and addresses
3153 DECL_PIOCTL(PListCells
)
3155 afs_int32 whichCell
;
3156 struct cell
*tcell
= 0;
3160 AFS_STATCNT(PListCells
);
3161 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3162 return EIO
; /* Inappropriate ioctl for device */
3164 if (afs_pd_getInt(ain
, &whichCell
) != 0)
3167 tcell
= afs_GetCellByIndex(whichCell
, READ_LOCK
);
3173 for (i
= 0; i
< AFS_MAXCELLHOSTS
; i
++) {
3174 if (tcell
->cellHosts
[i
] == 0)
3176 if (afs_pd_putInt(aout
, tcell
->cellHosts
[i
]->addr
->sa_ip
) != 0)
3179 for (;i
< AFS_MAXCELLHOSTS
; i
++) {
3180 if (afs_pd_putInt(aout
, 0) != 0)
3183 if (afs_pd_putString(aout
, tcell
->cellName
) != 0)
3188 afs_PutCell(tcell
, READ_LOCK
);
3192 DECL_PIOCTL(PListAliases
)
3194 afs_int32 whichAlias
;
3195 struct cell_alias
*tcalias
= 0;
3198 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3199 return EIO
; /* Inappropriate ioctl for device */
3201 if (afs_pd_getInt(ain
, &whichAlias
) != 0)
3204 tcalias
= afs_GetCellAlias(whichAlias
);
3205 if (tcalias
== NULL
)
3209 if (afs_pd_putString(aout
, tcalias
->alias
) != 0)
3211 if (afs_pd_putString(aout
, tcalias
->cell
) != 0)
3216 afs_PutCellAlias(tcalias
);
3221 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
3225 * \param[in] ain the name of the file in this dir to remove
3226 * \param[out] aout not in use
3229 * Error if some of the standard args aren't set
3231 * Error if the argument to remove is not a directory
3233 * Error if there is no cache to remove the mount point from or
3234 * if a vcache doesn't exist
3237 * Ensure that everything is OK before deleting the mountpoint.
3238 * If not, don't delete. Delete a mount point based on a file id.
3240 DECL_PIOCTL(PRemoveMount
)
3245 struct sysname_info sysState
;
3246 afs_size_t offset
, len
;
3247 struct afs_conn
*tc
;
3250 struct AFSFetchStatus OutDirStatus
;
3251 struct VenusFid tfid
;
3252 struct AFSVolSync tsync
;
3253 struct rx_connection
*rxconn
;
3256 /* "ain" is the name of the file in this dir to remove */
3258 AFS_STATCNT(PRemoveMount
);
3261 if (afs_pd_getStringPtr(ain
, &name
) != 0)
3264 code
= afs_VerifyVCache(avc
, areq
);
3267 if (vType(avc
) != VDIR
)
3270 tdc
= afs_GetDCache(avc
, (afs_size_t
) 0, areq
, &offset
, &len
, 1); /* test for error below */
3273 Check_AtSys(avc
, name
, &sysState
, areq
);
3274 ObtainReadLock(&tdc
->lock
);
3276 code
= afs_dir_Lookup(tdc
, sysState
.name
, &tfid
.Fid
);
3277 } while (code
== ENOENT
&& Next_AtSys(avc
, areq
, &sysState
));
3278 ReleaseReadLock(&tdc
->lock
);
3279 bufp
= sysState
.name
;
3284 tfid
.Cell
= avc
->f
.fid
.Cell
;
3285 tfid
.Fid
.Volume
= avc
->f
.fid
.Fid
.Volume
;
3286 if (!tfid
.Fid
.Unique
&& (avc
->f
.states
& CForeign
)) {
3287 tvc
= afs_LookupVCache(&tfid
, areq
, NULL
, avc
, bufp
);
3289 tvc
= afs_GetVCache(&tfid
, areq
, NULL
, NULL
);
3296 if (tvc
->mvstat
!= AFS_MVSTAT_MTPT
) {
3302 ObtainWriteLock(&tvc
->lock
, 230);
3303 code
= afs_HandleLink(tvc
, areq
);
3305 if (tvc
->linkData
) {
3306 if ((tvc
->linkData
[0] != '#') && (tvc
->linkData
[0] != '%'))
3311 ReleaseWriteLock(&tvc
->lock
);
3312 osi_dnlc_purgedp(tvc
);
3318 ObtainWriteLock(&avc
->lock
, 231);
3319 osi_dnlc_remove(avc
, bufp
, tvc
);
3321 tc
= afs_Conn(&avc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
3323 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE
);
3326 RXAFS_RemoveFile(rxconn
, (struct AFSFid
*)&avc
->f
.fid
.Fid
, bufp
,
3327 &OutDirStatus
, &tsync
);
3332 } while (afs_Analyze
3333 (tc
, rxconn
, code
, &avc
->f
.fid
, areq
, AFS_STATS_FS_RPCIDX_REMOVEFILE
,
3334 SHARED_LOCK
, NULL
));
3339 ReleaseWriteLock(&avc
->lock
);
3343 /* we have the thing in the cache */
3344 ObtainWriteLock(&tdc
->lock
, 661);
3345 if (afs_LocalHero(avc
, tdc
, &OutDirStatus
, 1)) {
3346 /* we can do it locally */
3347 code
= afs_dir_Delete(tdc
, bufp
);
3349 ZapDCE(tdc
); /* surprise error -- invalid value */
3353 ReleaseWriteLock(&tdc
->lock
);
3354 afs_PutDCache(tdc
); /* drop ref count */
3356 avc
->f
.states
&= ~CUnique
; /* For the dfs xlator */
3357 ReleaseWriteLock(&avc
->lock
);
3360 if (sysState
.allocked
)
3361 osi_FreeLargeSpace(bufp
);
3366 * VIOC_GETCELLSTATUS (35) - Get cell status info
3370 * \param[in] ain The cell you want status information on
3371 * \param[out] aout cell state (as a struct)
3373 * \retval EIO Error if the afs daemon hasn't started yet
3374 * \retval ENOENT Error if the cell doesn't exist
3376 * \post Returns the state of the cell as defined in a struct cell
3378 DECL_PIOCTL(PGetCellStatus
)
3384 AFS_STATCNT(PGetCellStatus
);
3385 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3386 return EIO
; /* Inappropriate ioctl for device */
3388 if (afs_pd_getStringPtr(ain
, &cellName
) != 0)
3391 tcell
= afs_GetCellByName(cellName
, READ_LOCK
);
3394 temp
= tcell
->states
;
3395 afs_PutCell(tcell
, READ_LOCK
);
3397 return afs_pd_putInt(aout
, temp
);
3401 * VIOC_SETCELLSTATUS (36) - Set corresponding info
3406 * The cell you want to set information about, and the values you
3411 * \retval EIO Error if the afs daemon hasn't started yet
3412 * \retval EACCES Error if the user doesn't have super-user credentials
3415 * Set the state of the cell in a defined struct cell, based on
3416 * whether or not SetUID is allowed
3418 DECL_PIOCTL(PSetCellStatus
)
3422 afs_int32 flags0
, flags1
;
3424 if (!afs_osi_suser(*acred
))
3426 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3427 return EIO
; /* Inappropriate ioctl for device */
3429 if (afs_pd_getInt(ain
, &flags0
) != 0)
3431 if (afs_pd_getInt(ain
, &flags1
) != 0)
3433 if (afs_pd_getStringPtr(ain
, &cellName
) != 0)
3436 tcell
= afs_GetCellByName(cellName
, WRITE_LOCK
);
3439 if (flags0
& CNoSUID
)
3440 tcell
->states
|= CNoSUID
;
3442 tcell
->states
&= ~CNoSUID
;
3443 afs_PutCell(tcell
, WRITE_LOCK
);
3448 FlushVolumeData(struct VenusFid
*afid
, afs_ucred_t
* acred
)
3456 afs_int32 volume
= 0;
3457 struct afs_q
*tq
, *uq
;
3458 #ifdef AFS_DARWIN80_ENV
3465 volume
= afid
->Fid
.Volume
; /* who to zap */
3470 * Clear stat'd flag from all vnodes from this volume; this will
3471 * invalidate all the vcaches associated with the volume.
3474 ObtainReadLock(&afs_xvcache
);
3475 for (i
= (afid
? VCHashV(afid
) : 0); i
< VCSIZE
; i
= (afid
? VCSIZE
: i
+1)) {
3476 for (tq
= afs_vhashTV
[i
].prev
; tq
!= &afs_vhashTV
[i
]; tq
= uq
) {
3479 if (all
|| (tvc
->f
.fid
.Fid
.Volume
== volume
&& tvc
->f
.fid
.Cell
== cell
)) {
3480 if (tvc
->f
.states
& CVInit
) {
3481 ReleaseReadLock(&afs_xvcache
);
3482 afs_osi_Sleep(&tvc
->f
.states
);
3485 #ifdef AFS_DARWIN80_ENV
3486 if (tvc
->f
.states
& CDeadVnode
) {
3487 ReleaseReadLock(&afs_xvcache
);
3488 afs_osi_Sleep(&tvc
->f
.states
);
3494 if (vnode_ref(vp
)) {
3503 ReleaseReadLock(&afs_xvcache
);
3504 ObtainWriteLock(&tvc
->lock
, 232);
3505 afs_ResetVCache(tvc
, acred
, 1);
3506 ReleaseWriteLock(&tvc
->lock
);
3507 #ifdef AFS_DARWIN80_ENV
3508 vnode_put(AFSTOV(tvc
));
3510 ObtainReadLock(&afs_xvcache
);
3512 /* our tvc ptr is still good until now */
3517 ReleaseReadLock(&afs_xvcache
);
3520 ObtainWriteLock(&afs_xdcache
, 328); /* needed to flush any stuff */
3521 for (i
= 0; i
< afs_cacheFiles
; i
++) {
3522 if (!(afs_indexFlags
[i
] & IFEverUsed
))
3523 continue; /* never had any data */
3524 tdc
= afs_GetValidDSlot(i
);
3528 if (tdc
->refCount
<= 1) { /* too high, in use by running sys call */
3529 ReleaseReadLock(&tdc
->tlock
);
3530 if (all
|| (tdc
->f
.fid
.Fid
.Volume
== volume
&& tdc
->f
.fid
.Cell
== cell
)) {
3531 if (!(afs_indexFlags
[i
] & (IFDataMod
| IFFree
| IFDiscarded
))) {
3532 /* if the file is modified, but has a ref cnt of only 1,
3533 * then someone probably has the file open and is writing
3534 * into it. Better to skip flushing such a file, it will be
3535 * brought back immediately on the next write anyway.
3537 * Skip if already freed.
3539 * If we *must* flush, then this code has to be rearranged
3540 * to call afs_storeAllSegments() first */
3541 afs_FlushDCache(tdc
);
3545 ReleaseReadLock(&tdc
->tlock
);
3547 afs_PutDCache(tdc
); /* bumped by getdslot */
3549 ReleaseWriteLock(&afs_xdcache
);
3551 ObtainReadLock(&afs_xvolume
);
3552 for (i
= all
? 0 : VHash(volume
); i
< NVOLS
; i
++) {
3553 for (tv
= afs_volumes
[i
]; tv
; tv
= tv
->next
) {
3554 if (all
|| tv
->volume
== volume
) {
3555 afs_ResetVolumeInfo(tv
);
3562 ReleaseReadLock(&afs_xvolume
);
3564 /* probably, a user is doing this, probably, because things are screwed up.
3565 * maybe it's the dnlc's fault? */
3570 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
3574 * \param[in] ain not in use (args in avc)
3575 * \param[out] aout not in use
3577 * \retval EINVAL Error if some of the standard args aren't set
3578 * \retval EIO Error if the afs daemon hasn't started yet
3581 * Flush all cached contents of a volume. Exactly what stays and what
3582 * goes depends on the platform.
3585 * Does not flush a file that a user has open and is using, because
3586 * it will be re-created on next write. Also purges the dnlc,
3587 * because things are screwed up.
3589 DECL_PIOCTL(PFlushVolumeData
)
3591 AFS_STATCNT(PFlushVolumeData
);
3594 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3595 return EIO
; /* Inappropriate ioctl for device */
3597 FlushVolumeData(&avc
->f
.fid
, *acred
);
3602 * VIOC_FLUSHALL (14) - Flush whole volume's data for all volumes
3606 * \param[in] ain not in use
3607 * \param[out] aout not in use
3609 * \retval EINVAL Error if some of the standard args aren't set
3610 * \retval EIO Error if the afs daemon hasn't started yet
3613 * Flush all cached contents. Exactly what stays and what
3614 * goes depends on the platform.
3617 * Does not flush a file that a user has open and is using, because
3618 * it will be re-created on next write. Also purges the dnlc,
3619 * because things are screwed up.
3621 DECL_PIOCTL(PFlushAllVolumeData
)
3623 AFS_STATCNT(PFlushAllVolumeData
);
3625 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3626 return EIO
; /* Inappropriate ioctl for device */
3628 FlushVolumeData(NULL
, *acred
);
3633 * VIOCGETVCXSTATUS (41) - gets vnode x status
3638 * not in use (avc used)
3640 * vcxstat: the file id, the data version, any lock, the parent vnode,
3641 * the parent unique id, the trunc position, the callback, cbExpires,
3642 * what access is being made, what files are open,
3643 * any users executing/writing, the flock count, the states,
3647 * Error if some of the initial default arguments aren't set
3649 * Error if access to check the mode bits is denied
3652 * gets stats for the vnode, a struct listed in vcxstat
3654 DECL_PIOCTL(PGetVnodeXStatus
)
3657 struct vcxstat stat
;
3660 /* AFS_STATCNT(PGetVnodeXStatus); */
3663 code
= afs_VerifyVCache(avc
, areq
);
3666 if (vType(avc
) == VDIR
)
3667 mode
= PRSFS_LOOKUP
;
3670 if (!afs_AccessOK(avc
, mode
, areq
, CHECK_MODE_BITS
))
3673 memset(&stat
, 0, sizeof(struct vcxstat
));
3674 stat
.fid
= avc
->f
.fid
;
3675 hset32(stat
.DataVersion
, hgetlo(avc
->f
.m
.DataVersion
));
3676 stat
.lock
= avc
->lock
;
3677 stat
.parentVnode
= avc
->f
.parent
.vnode
;
3678 stat
.parentUnique
= avc
->f
.parent
.unique
;
3679 hset(stat
.flushDV
, avc
->flushDV
);
3680 hset(stat
.mapDV
, avc
->mapDV
);
3681 stat
.truncPos
= avc
->f
.truncPos
;
3682 { /* just grab the first two - won't break anything... */
3683 struct axscache
*ac
;
3685 for (i
= 0, ac
= avc
->Access
; ac
&& i
< CPSIZE
; i
++, ac
= ac
->next
) {
3686 stat
.randomUid
[i
] = ac
->uid
;
3687 stat
.randomAccess
[i
] = ac
->axess
;
3690 stat
.callback
= afs_data_pointer_to_int32(avc
->callback
);
3691 stat
.cbExpires
= avc
->cbExpires
;
3692 stat
.anyAccess
= avc
->f
.anyAccess
;
3693 stat
.opens
= avc
->opens
;
3694 stat
.execsOrWriters
= avc
->execsOrWriters
;
3695 stat
.flockCount
= avc
->flockCount
;
3696 stat
.mvstat
= avc
->mvstat
;
3697 stat
.states
= avc
->f
.states
;
3698 return afs_pd_putBytes(aout
, &stat
, sizeof(struct vcxstat
));
3702 DECL_PIOCTL(PGetVnodeXStatus2
)
3705 struct vcxstat2 stat
;
3710 code
= afs_VerifyVCache(avc
, areq
);
3713 if (vType(avc
) == VDIR
)
3714 mode
= PRSFS_LOOKUP
;
3717 if (!afs_AccessOK(avc
, mode
, areq
, CHECK_MODE_BITS
))
3720 memset(&stat
, 0, sizeof(struct vcxstat2
));
3722 stat
.cbExpires
= avc
->cbExpires
;
3723 stat
.anyAccess
= avc
->f
.anyAccess
;
3724 stat
.mvstat
= avc
->mvstat
;
3725 stat
.callerAccess
= afs_GetAccessBits(avc
, ~0, areq
);
3727 return afs_pd_putBytes(aout
, &stat
, sizeof(struct vcxstat2
));
3732 * VIOC_AFS_SYSNAME (38) - Change @sys value
3736 * \param[in] ain new value for @sys
3737 * \param[out] aout count, entry, list (debug values?)
3740 * Error if afsd isn't running, the new sysname is too large,
3741 * the new sysname causes issues (starts with a . or ..),
3742 * there is no PAG set in the credentials, or the user of a PAG
3745 * Error if the user doesn't have super-user credentials
3748 * Set the value of @sys if these things work: if the input isn't
3749 * too long or if input doesn't start with . or ..
3752 * We require root for local sysname changes, but not for remote
3753 * (since we don't really believe remote uids anyway)
3754 * outname[] shouldn't really be needed- this is left as an
3755 * exercise for the reader.
3757 DECL_PIOCTL(PSetSysName
)
3759 char *inname
= NULL
;
3760 char outname
[MAXSYSNAME
];
3761 afs_int32 setsysname
;
3763 struct afs_exporter
*exporter
;
3764 struct unixuser
*au
;
3765 afs_int32 pag
, error
;
3766 int t
, count
, num
= 0, allpags
= 0;
3768 struct afs_pdata validate
;
3770 AFS_STATCNT(PSetSysName
);
3771 if (!afs_globalVFS
) {
3772 /* Afsd is NOT running; disable it */
3773 #if defined(KERNEL_HAVE_UERROR)
3774 return (setuerror(EINVAL
), EINVAL
);
3779 if (afs_pd_getInt(ain
, &setsysname
) != 0)
3781 if (setsysname
& 0x8000) {
3783 setsysname
&= ~0x8000;
3788 if (setsysname
< 0 || setsysname
> MAXNUMSYSNAMES
)
3791 for (count
= 0; count
< setsysname
; count
++) {
3792 if (afs_pd_getStringPtr(&validate
, &inname
) != 0)
3795 if (t
>= MAXSYSNAME
|| t
<= 0)
3797 /* check for names that can shoot us in the foot */
3798 if (inname
[0] == '.' && (inname
[1] == 0
3799 || (inname
[1] == '.' && inname
[2] == 0)))
3802 /* args ok, so go back to the beginning of that section */
3804 if (afs_pd_getStringPtr(ain
, &inname
) != 0)
3808 if (afs_rmtsys_enable
&& (afs_cr_gid(*acred
) == RMTUSER_REQ
||
3809 afs_cr_gid(*acred
) == RMTUSER_REQ_PRIV
)) { /* Handles all exporters */
3810 if (allpags
&& afs_cr_gid(*acred
) != RMTUSER_REQ_PRIV
) {
3813 pag
= PagInCred(*acred
);
3815 return EINVAL
; /* Better than panicing */
3817 if (!(au
= afs_FindUser(pag
, -1, READ_LOCK
))) {
3818 return EINVAL
; /* Better than panicing */
3820 if (!(exporter
= au
->exporter
)) {
3821 afs_PutUser(au
, READ_LOCK
);
3822 return EINVAL
; /* Better than panicing */
3824 error
= EXP_SYSNAME(exporter
, inname
, &sysnamelist
,
3827 if (error
== ENODEV
)
3828 foundname
= 0; /* sysname not set yet! */
3830 afs_PutUser(au
, READ_LOCK
);
3835 strcpy(outname
, sysnamelist
[0]);
3837 afs_PutUser(au
, READ_LOCK
);
3841 /* Not xlating, so local case */
3843 osi_Panic("PSetSysName: !afs_sysname\n");
3844 if (!setsysname
) { /* user just wants the info */
3845 strcpy(outname
, afs_sysname
);
3846 foundname
= afs_sysnamecount
;
3847 sysnamelist
= afs_sysnamelist
;
3848 } else { /* Local guy; only root can change sysname */
3849 if (!afs_osi_suser(*acred
))
3852 /* allpags makes no sense for local use */
3856 /* clear @sys entries from the dnlc, once afs_lookup can
3857 * do lookups of @sys entries and thinks it can trust them */
3858 /* privs ok, store the entry, ... */
3860 if (strlen(inname
) >= MAXSYSNAME
-1)
3862 strcpy(afs_sysname
, inname
);
3864 if (setsysname
> 1) { /* ... or list */
3865 for (count
= 1; count
< setsysname
; ++count
) {
3866 if (!afs_sysnamelist
[count
])
3868 ("PSetSysName: no afs_sysnamelist entry to write\n");
3869 if (afs_pd_getString(ain
, afs_sysnamelist
[count
],
3874 afs_sysnamecount
= setsysname
;
3879 if (afs_pd_putInt(aout
, foundname
) != 0)
3882 if (afs_pd_putString(aout
, outname
) != 0)
3884 for (count
= 1; count
< foundname
; ++count
) { /* ... or list. */
3885 if (!sysnamelist
[count
])
3887 ("PSetSysName: no afs_sysnamelist entry to read\n");
3888 t
= strlen(sysnamelist
[count
]);
3889 if (t
>= MAXSYSNAME
)
3890 osi_Panic("PSetSysName: sysname entry garbled\n");
3891 if (afs_pd_putString(aout
, sysnamelist
[count
]) != 0)
3899 /* sequential search through the list of touched cells is not a good
3900 * long-term solution here. For small n, though, it should be just
3901 * fine. Should consider special-casing the local cell for large n.
3902 * Likewise for PSetSPrefs.
3904 * s - number of ids in array l[] -- NOT index of last id
3905 * l - array of cell ids which have volumes that need to be sorted
3906 * vlonly - sort vl servers or file servers?
3909 ReSortCells_cb(struct cell
*cell
, void *arg
)
3911 afs_int32
*p
= (afs_int32
*) arg
;
3912 afs_int32
*l
= p
+ 1;
3915 for (i
= 0; i
< s
; i
++) {
3916 if (l
[i
] == cell
->cellNum
) {
3917 ObtainWriteLock(&cell
->lock
, 690);
3918 afs_SortServers(cell
->cellHosts
, AFS_MAXCELLHOSTS
);
3919 ReleaseWriteLock(&cell
->lock
);
3927 ReSortCells(int s
, afs_int32
* l
, int vlonly
)
3935 p
= afs_osi_Alloc(sizeof(afs_int32
) * (s
+ 1));
3936 osi_Assert(p
!= NULL
);
3938 memcpy(p
+ 1, l
, s
* sizeof(afs_int32
));
3939 afs_TraverseCells(&ReSortCells_cb
, p
);
3940 afs_osi_Free(p
, sizeof(afs_int32
) * (s
+ 1));
3944 ObtainReadLock(&afs_xvolume
);
3945 for (i
= 0; i
< NVOLS
; i
++) {
3946 for (j
= afs_volumes
[i
]; j
; j
= j
->next
) {
3947 for (k
= 0; k
< s
; k
++)
3948 if (j
->cell
== l
[k
]) {
3949 ObtainWriteLock(&j
->lock
, 233);
3950 afs_SortServers(j
->serverHost
, AFS_MAXHOSTS
);
3951 ReleaseWriteLock(&j
->lock
);
3956 ReleaseReadLock(&afs_xvolume
);
3960 static int debugsetsp
= 0;
3962 afs_setsprefs(struct spref
*sp
, unsigned int num
, unsigned int vlonly
)
3965 int i
, j
, k
, matches
, touchedSize
;
3966 struct server
*srvr
= NULL
;
3967 afs_int32 touched
[34];
3971 for (k
= 0; k
< num
; sp
++, k
++) {
3973 afs_warn("sp host=%x, rank=%d\n", sp
->host
.s_addr
, sp
->rank
);
3976 ObtainReadLock(&afs_xserver
);
3978 i
= SHash(sp
->host
.s_addr
);
3979 for (sa
= afs_srvAddrs
[i
]; sa
; sa
= sa
->next_bkt
) {
3980 if (sa
->sa_ip
== sp
->host
.s_addr
) {
3982 isfs
= (srvr
->cell
&& (sa
->sa_portal
== srvr
->cell
->fsport
))
3983 || (sa
->sa_portal
== AFS_FSPORT
);
3984 if ((!vlonly
&& isfs
) || (vlonly
&& !isfs
)) {
3991 if (sa
&& matches
) { /* found one! */
3993 afs_warn("sa ip=%x, ip_rank=%d\n", sa
->sa_ip
, sa
->sa_iprank
);
3995 sa
->sa_iprank
= sp
->rank
+ afs_randomMod15();
3996 afs_SortOneServer(sa
->server
);
3999 /* if we don't know yet what cell it's in, this is moot */
4000 for (j
= touchedSize
- 1;
4001 j
>= 0 && touched
[j
] != srvr
->cell
->cellNum
; j
--)
4002 /* is it in our list of touched cells ? */ ;
4003 if (j
< 0) { /* no, it's not */
4004 touched
[touchedSize
++] = srvr
->cell
->cellNum
;
4005 if (touchedSize
>= 32) { /* watch for ovrflow */
4006 ReleaseReadLock(&afs_xserver
);
4007 ReSortCells(touchedSize
, touched
, vlonly
);
4009 ObtainReadLock(&afs_xserver
);
4015 ReleaseReadLock(&afs_xserver
);
4016 /* if we didn't find one, start to create one. */
4017 /* Note that it doesn't have a cell yet... */
4019 afs_uint32 temp
= sp
->host
.s_addr
;
4021 afs_GetServer(&temp
, 1, 0, (vlonly
? AFS_VLPORT
: AFS_FSPORT
),
4022 WRITE_LOCK
, (afsUUID
*) 0, 0, NULL
);
4023 srvr
->addr
->sa_iprank
= sp
->rank
+ afs_randomMod15();
4024 afs_PutServer(srvr
, WRITE_LOCK
);
4026 } /* for all cited preferences */
4028 ReSortCells(touchedSize
, touched
, vlonly
);
4033 * VIOC_SETPREFS (46) - Set server ranks
4035 * \param[in] ain the sprefs value you want the sprefs to be set to
4036 * \param[out] aout not in use
4039 * Error if the afs daemon hasn't started yet
4041 * Error if the user doesn't have super-user credentials
4043 * Error if the struct setsprefs is too large or if it multiplied
4044 * by the number of servers is too large
4046 * \post set the sprefs using the afs_setsprefs() function
4048 DECL_PIOCTL(PSetSPrefs
)
4050 struct setspref
*ssp
;
4054 AFS_STATCNT(PSetSPrefs
);
4056 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4057 return EIO
; /* Inappropriate ioctl for device */
4059 if (!afs_osi_suser(*acred
))
4062 /* The I/O handling here is ghastly, as it relies on overrunning the ends
4063 * of arrays. But, i'm not quite brave enough to change it yet. */
4065 ainSize
= ain
->remaining
;
4067 if (ainSize
< sizeof(struct setspref
))
4070 ssp
= (struct setspref
*)ainPtr
;
4071 if (ainSize
< (sizeof(struct setspref
)
4072 + sizeof(struct spref
) * (ssp
->num_servers
-1)))
4075 afs_setsprefs(&(ssp
->servers
[0]), ssp
->num_servers
,
4076 (ssp
->flags
& DBservers
));
4081 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
4083 * \param[in] ain the server preferences to be set
4084 * \param[out] aout not in use
4086 * \retval EIO Error if the afs daemon hasn't started yet
4087 * \retval EACCES Error if the user doesn't have super-user credentials
4089 * \post set the server preferences, calling a function
4091 * \notes this may only be performed by the local root user.
4093 DECL_PIOCTL(PSetSPrefs33
)
4095 AFS_STATCNT(PSetSPrefs
);
4096 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4097 return EIO
; /* Inappropriate ioctl for device */
4100 if (!afs_osi_suser(*acred
))
4103 afs_setsprefs((struct spref
*)afs_pd_where(ain
),
4104 afs_pd_remaining(ain
) / sizeof(struct spref
),
4110 * VIOC_GETSPREFS (43) - Get server ranks
4114 * \param[in] ain the server preferences to get
4115 * \param[out] aout the server preferences information
4117 * \retval EIO Error if the afs daemon hasn't started yet
4118 * \retval ENOENT Error if the sprefrequest is too large
4120 * \post Get the sprefs
4123 * in the hash table of server structs, all servers with the same
4124 * IP address; will be on the same overflow chain; This could be
4125 * sped slightly in some circumstances by having it cache the
4126 * immediately previous slot in the hash table and some
4127 * supporting information; Only reports file servers now.
4129 DECL_PIOCTL(PGetSPrefs
)
4131 struct sprefrequest spin
; /* input */
4132 struct sprefinfo
*spout
; /* output */
4133 struct spref
*srvout
; /* one output component */
4134 int i
, j
; /* counters for hash table traversal */
4135 struct server
*srvr
; /* one of CM's server structs */
4137 int vlonly
; /* just return vlservers ? */
4140 AFS_STATCNT(PGetSPrefs
);
4141 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4142 return EIO
; /* Inappropriate ioctl for device */
4144 /* Work out from the size whether we've got a new, or old, style pioctl */
4145 if (afs_pd_remaining(ain
) < sizeof(struct sprefrequest
)) {
4146 if (afs_pd_getBytes(ain
, &spin
, sizeof(struct sprefrequest_33
)) != 0)
4151 if (afs_pd_getBytes(ain
, &spin
, sizeof(struct sprefrequest
)) != 0)
4153 vlonly
= (spin
.flags
& DBservers
);
4156 /* This code relies on overflowing arrays. It's ghastly, but I'm not
4157 * quite brave enough to tackle it yet ...
4160 /* struct sprefinfo includes 1 server struct... that size gets added
4161 * in during the loop that follows.
4163 spout
= afs_pd_inline(aout
,
4164 sizeof(struct sprefinfo
) - sizeof(struct spref
));
4165 spout
->next_offset
= spin
.offset
;
4166 spout
->num_servers
= 0;
4167 srvout
= spout
->servers
;
4169 ObtainReadLock(&afs_xserver
);
4170 for (i
= 0, j
= 0; j
< NSERVERS
; j
++) { /* sift through hash table */
4171 for (sa
= afs_srvAddrs
[j
]; sa
; sa
= sa
->next_bkt
, i
++) {
4172 if (spin
.offset
> (unsigned short)i
) {
4173 continue; /* catch up to where we left off */
4175 spout
->next_offset
++;
4178 isfs
= (srvr
->cell
&& (sa
->sa_portal
== srvr
->cell
->fsport
))
4179 || (sa
->sa_portal
== AFS_FSPORT
);
4181 if ((vlonly
&& isfs
) || (!vlonly
&& !isfs
)) {
4182 /* only report ranks for vl servers */
4186 /* Check we've actually got the space we're about to use */
4187 if (afs_pd_inline(aout
, sizeof(struct spref
)) == NULL
) {
4188 ReleaseReadLock(&afs_xserver
); /* no more room! */
4192 srvout
->host
.s_addr
= sa
->sa_ip
;
4193 srvout
->rank
= sa
->sa_iprank
;
4194 spout
->num_servers
++;
4198 ReleaseReadLock(&afs_xserver
);
4200 spout
->next_offset
= 0; /* start over from the beginning next time */
4205 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
4206 int afs_NFSRootOnly
= 1;
4208 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
4213 * an integer containing the desired exportee flags
4215 * an integer containing the current exporter flags
4217 * \retval ENODEV Error if the exporter doesn't exist
4218 * \retval EACCES Error if the user doesn't have super-user credentials
4221 * Changes the state of various values to reflect the change
4222 * of the export values between nfs and afs.
4224 * \notes Legacy code obtained from IBM.
4226 DECL_PIOCTL(PExportAfs
)
4228 afs_int32 export
, newint
= 0;
4229 afs_int32 type
, changestate
, handleValue
, convmode
, pwsync
, smounts
;
4230 afs_int32 rempags
= 0, pagcb
= 0;
4231 struct afs_exporter
*exporter
;
4233 AFS_STATCNT(PExportAfs
);
4234 if (afs_pd_getInt(ain
, &handleValue
) != 0)
4236 type
= handleValue
>> 24;
4241 exporter
= exporter_find(type
);
4243 export
= handleValue
& 3;
4244 changestate
= handleValue
& 0xfff;
4245 smounts
= (handleValue
>> 2) & 3;
4246 pwsync
= (handleValue
>> 4) & 3;
4247 convmode
= (handleValue
>> 6) & 3;
4248 rempags
= (handleValue
>> 8) & 3;
4249 pagcb
= (handleValue
>> 10) & 3;
4251 changestate
= (handleValue
>> 16) & 0x1;
4252 convmode
= (handleValue
>> 16) & 0x2;
4253 pwsync
= (handleValue
>> 16) & 0x4;
4254 smounts
= (handleValue
>> 16) & 0x8;
4255 export
= handleValue
& 0xff;
4258 /* Failed finding desired exporter; */
4262 handleValue
= exporter
->exp_states
;
4263 if (afs_pd_putInt(aout
, handleValue
) != 0)
4266 if (!afs_osi_suser(*acred
))
4267 return EACCES
; /* Only superuser can do this */
4271 exporter
->exp_states
|= EXP_EXPORTED
;
4273 exporter
->exp_states
&= ~EXP_EXPORTED
;
4277 exporter
->exp_states
|= EXP_UNIXMODE
;
4279 exporter
->exp_states
&= ~EXP_UNIXMODE
;
4283 exporter
->exp_states
|= EXP_PWSYNC
;
4285 exporter
->exp_states
&= ~EXP_PWSYNC
;
4289 afs_NFSRootOnly
= 0;
4290 exporter
->exp_states
|= EXP_SUBMOUNTS
;
4292 afs_NFSRootOnly
= 1;
4293 exporter
->exp_states
&= ~EXP_SUBMOUNTS
;
4298 exporter
->exp_states
|= EXP_CLIPAGS
;
4300 exporter
->exp_states
&= ~EXP_CLIPAGS
;
4304 exporter
->exp_states
|= EXP_CALLBACK
;
4306 exporter
->exp_states
&= ~EXP_CALLBACK
;
4308 handleValue
= exporter
->exp_states
;
4309 if (afs_pd_putInt(aout
, handleValue
) != 0)
4313 exporter
->exp_states
|= EXP_EXPORTED
;
4315 exporter
->exp_states
&= ~EXP_EXPORTED
;
4317 exporter
->exp_states
|= EXP_UNIXMODE
;
4319 exporter
->exp_states
&= ~EXP_UNIXMODE
;
4321 exporter
->exp_states
|= EXP_PWSYNC
;
4323 exporter
->exp_states
&= ~EXP_PWSYNC
;
4325 afs_NFSRootOnly
= 0;
4326 exporter
->exp_states
|= EXP_SUBMOUNTS
;
4328 afs_NFSRootOnly
= 1;
4329 exporter
->exp_states
&= ~EXP_SUBMOUNTS
;
4338 * VIOC_GAG (44) - Silence Cache Manager
4342 * \param[in] ain the flags to either gag or de-gag the cache manager
4343 * \param[out] aout not in use
4345 * \retval EACCES Error if the user doesn't have super-user credentials
4347 * \post set the gag flags, then show these flags
4351 struct gaginfo
*gagflags
;
4353 if (!afs_osi_suser(*acred
))
4356 gagflags
= afs_pd_inline(ain
, sizeof(*gagflags
));
4357 if (gagflags
== NULL
)
4359 afs_showflags
= gagflags
->showflags
;
4365 * VIOC_TWIDDLE (45) - Adjust RX knobs
4369 * \param[in] ain the previous settings of the 'knobs'
4370 * \param[out] aout not in use
4372 * \retval EACCES Error if the user doesn't have super-user credentials
4374 * \post build out the struct rxp, from a struct rx
4376 DECL_PIOCTL(PTwiddleRx
)
4378 struct rxparams
*rxp
;
4380 if (!afs_osi_suser(*acred
))
4383 rxp
= afs_pd_inline(ain
, sizeof(*rxp
));
4387 if (rxp
->rx_initReceiveWindow
)
4388 rx_initReceiveWindow
= rxp
->rx_initReceiveWindow
;
4389 if (rxp
->rx_maxReceiveWindow
)
4390 rx_maxReceiveWindow
= rxp
->rx_maxReceiveWindow
;
4391 if (rxp
->rx_initSendWindow
)
4392 rx_initSendWindow
= rxp
->rx_initSendWindow
;
4393 if (rxp
->rx_maxSendWindow
)
4394 rx_maxSendWindow
= rxp
->rx_maxSendWindow
;
4395 if (rxp
->rxi_nSendFrags
)
4396 rxi_nSendFrags
= rxp
->rxi_nSendFrags
;
4397 if (rxp
->rxi_nRecvFrags
)
4398 rxi_nRecvFrags
= rxp
->rxi_nRecvFrags
;
4399 if (rxp
->rxi_OrphanFragSize
)
4400 rxi_OrphanFragSize
= rxp
->rxi_OrphanFragSize
;
4401 if (rxp
->rx_maxReceiveSize
) {
4402 rx_maxReceiveSize
= rxp
->rx_maxReceiveSize
;
4403 rx_maxReceiveSizeUser
= rxp
->rx_maxReceiveSize
;
4405 if (rxp
->rx_MyMaxSendSize
)
4406 rx_MyMaxSendSize
= rxp
->rx_MyMaxSendSize
;
4412 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
4416 * \param[in] ain not in use
4417 * \param[out] aout initial cache manager params
4420 * Error if the initial parameters are bigger than some PIGGYSIZE
4422 * \post return the initial cache manager parameters
4424 DECL_PIOCTL(PGetInitParams
)
4426 if (sizeof(struct cm_initparams
) > PIGGYSIZE
)
4429 return afs_pd_putBytes(aout
, &cm_initParams
,
4430 sizeof(struct cm_initparams
));
4433 #ifdef AFS_SGI65_ENV
4434 /* They took crget() from us, so fake it. */
4439 cr
= crdup(get_current_cred());
4440 memset(cr
, 0, sizeof(cred_t
));
4441 #if CELL || CELL_PREPARE
4449 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
4453 * \param[in] ain not in use
4454 * \param[out] aout value of cryptall
4456 * \post Turns on, or disables, rxkad encryption by setting the cryptall global
4458 DECL_PIOCTL(PGetRxkcrypt
)
4460 return afs_pd_putInt(aout
, cryptall
);
4464 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
4468 * \param[in] ain the argument whether or not things should be encrypted
4469 * \param[out] aout not in use
4472 * Error if the user doesn't have super-user credentials
4474 * Error if the input is too big, or if the input is outside the
4475 * bounds of what it can be set to
4477 * \post set whether or not things should be encrypted
4480 * may need to be modified at a later date to take into account
4481 * other values for cryptall (beyond true or false)
4483 DECL_PIOCTL(PSetRxkcrypt
)
4487 if (!afs_osi_suser(*acred
))
4489 if (afs_pd_getInt(ain
, &tmpval
) != 0)
4491 /* if new mappings added later this will need to be changed */
4492 if (tmpval
!= 0 && tmpval
!= 1)
4498 #ifdef AFS_NEED_CLIENTCONTEXT
4500 * Create new credentials to correspond to a remote user with given
4501 * <hostaddr, uid, g0, g1>. This allows a server running as root to
4502 * provide pioctl (and other) services to foreign clients (i.e. nfs
4503 * clients) by using this call to `become' the client.
4506 #define PIOCTL_HEADER 6
4508 HandleClientContext(struct afs_ioctl
*ablob
, int *com
,
4509 afs_ucred_t
**acred
, afs_ucred_t
*credp
)
4512 afs_uint32 hostaddr
;
4513 afs_int32 uid
, g0
, g1
, i
, code
, pag
, exporter_type
, isroot
= 0;
4514 struct afs_exporter
*exporter
, *outexporter
;
4515 afs_ucred_t
*newcred
;
4516 struct unixuser
*au
;
4517 afs_uint32 comp
= *com
& 0xff00;
4519 #if defined(AFS_SUN510_ENV)
4523 #if defined(AFS_SGIMP_ENV)
4524 osi_Assert(ISAFS_GLOCK());
4526 AFS_STATCNT(HandleClientContext
);
4527 if (ablob
->in_size
< PIOCTL_HEADER
* sizeof(afs_int32
)) {
4528 /* Must at least include the PIOCTL_HEADER header words
4529 * required by the protocol */
4530 return EINVAL
; /* Too small to be good */
4532 ain
= inData
= osi_AllocLargeSpace(AFS_LRALLOCSIZ
);
4533 AFS_COPYIN(ablob
->in
, ain
, PIOCTL_HEADER
* sizeof(afs_int32
), code
);
4535 osi_FreeLargeSpace(inData
);
4539 /* Extract information for remote user */
4540 hostaddr
= *((afs_uint32
*) ain
);
4541 ain
+= sizeof(hostaddr
);
4542 uid
= *((afs_uint32
*) ain
);
4544 g0
= *((afs_uint32
*) ain
);
4546 g1
= *((afs_uint32
*) ain
);
4548 *com
= *((afs_uint32
*) ain
);
4549 ain
+= sizeof(afs_int32
);
4550 exporter_type
= *((afs_uint32
*) ain
);/* In case we support more than NFS */
4553 * Of course, one must be root for most of these functions, but
4554 * we'll allow (for knfs) you to set things if the pag is 0 and
4555 * you're setting tokens or unlogging.
4558 if (!afs_osi_suser(credp
)) {
4559 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4560 /* Since SGI's suser() returns explicit failure after the call.. */
4563 /* check for acceptable opcodes for normal folks, which are, so far,
4564 * get/set tokens, sysname, and unlog.
4566 if (i
!= 9 && i
!= 3 && i
!= 38 && i
!= 8) {
4567 osi_FreeLargeSpace(inData
);
4572 ablob
->in_size
-= PIOCTL_HEADER
* sizeof(afs_int32
);
4573 ablob
->in
+= PIOCTL_HEADER
* sizeof(afs_int32
);
4574 osi_FreeLargeSpace(inData
);
4577 * We map uid 0 to nobody to match the mapping that the nfs
4578 * server does and to ensure that the suser() calls in the afs
4579 * code fails for remote client roots.
4581 uid
= afs_nobody
; /* NFS_NOBODY == -2 */
4585 #ifdef AFS_AIX41_ENV
4588 afs_set_cr_gid(newcred
, isroot
? RMTUSER_REQ_PRIV
: RMTUSER_REQ
);
4589 #ifdef AFS_AIX51_ENV
4590 newcred
->cr_groupset
.gs_union
.un_groups
[0] = g0
;
4591 newcred
->cr_groupset
.gs_union
.un_groups
[1] = g1
;
4592 #elif defined(AFS_LINUX26_ENV)
4593 # ifdef AFS_PAG_ONEGROUP_ENV
4594 afs_set_cr_group_info(newcred
, groups_alloc(1)); /* nothing sets this */
4595 l
= (((g0
-0x3f00) & 0x3fff) << 14) | ((g1
-0x3f00) & 0x3fff);
4596 h
= ((g0
-0x3f00) >> 14);
4597 h
= ((g1
-0x3f00) >> 14) + h
+ h
+ h
;
4598 GROUP_AT(afs_cr_group_info(newcred
), 0) = ((h
<< 28) | l
);
4600 afs_set_cr_group_info(newcred
, groups_alloc(2));
4601 GROUP_AT(afs_cr_group_info(newcred
), 0) = g0
;
4602 GROUP_AT(afs_cr_group_info(newcred
), 1) = g1
;
4604 #elif defined(AFS_SUN510_ENV)
4605 # ifdef AFS_PAG_ONEGROUP_ENV
4606 gids
[0] = afs_get_pag_from_groups(g0
, g1
);
4607 crsetgroups(newcred
, 1, gids
);
4611 crsetgroups(newcred
, 2, gids
);
4612 # endif /* !AFS_PAG_ONEGROUP_ENV */
4614 newcred
->cr_groups
[0] = g0
;
4615 newcred
->cr_groups
[1] = g1
;
4618 newcred
->cr_ngrps
= 2;
4619 #elif !defined(AFS_LINUX26_ENV) && !defined(AFS_SUN510_ENV)
4620 # if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_FBSD80_ENV)
4621 newcred
->cr_ngroups
= 2;
4623 for (i
= 2; i
< NGROUPS
; i
++)
4624 newcred
->cr_groups
[i
] = NOGROUP
;
4627 if (!(exporter
= exporter_find(exporter_type
))) {
4628 /* Exporter wasn't initialized or an invalid exporter type */
4632 if (exporter
->exp_states
& EXP_PWSYNC
) {
4633 if (uid
!= afs_cr_uid(credp
)) {
4635 return ENOEXEC
; /* XXX Find a better errno XXX */
4638 afs_set_cr_uid(newcred
, uid
); /* Only temporary */
4639 code
= EXP_REQHANDLER(exporter
, &newcred
, hostaddr
, &pag
, &outexporter
);
4640 /* The client's pag is the only unique identifier for it */
4641 afs_set_cr_uid(newcred
, pag
);
4643 if (!code
&& *com
== PSETPAG
) {
4644 /* Special case for 'setpag' */
4645 afs_uint32 pagvalue
= genpag();
4647 au
= afs_GetUser(pagvalue
, -1, WRITE_LOCK
); /* a new unixuser struct */
4649 * Note that we leave the 'outexporter' struct held so it won't
4652 au
->exporter
= outexporter
;
4653 if (ablob
->out_size
>= 4) {
4654 AFS_COPYOUT((char *)&pagvalue
, ablob
->out
, sizeof(afs_int32
),
4657 afs_PutUser(au
, WRITE_LOCK
);
4660 return PSETPAG
; /* Special return for setpag */
4662 EXP_RELE(outexporter
);
4665 *com
= (*com
) | comp
;
4668 #endif /* AFS_NEED_CLIENTCONTEXT */
4672 * VIOC_GETCPREFS (50) - Get client interface
4676 * \param[in] ain sprefrequest input
4677 * \param[out] aout spref information
4679 * \retval EIO Error if the afs daemon hasn't started yet
4680 * \retval EINVAL Error if some of the standard args aren't set
4683 * get all interface addresses and other information of the client
4686 DECL_PIOCTL(PGetCPrefs
)
4688 struct sprefrequest
*spin
; /* input */
4689 struct sprefinfo
*spout
; /* output */
4690 struct spref
*srvout
; /* one output component */
4694 AFS_STATCNT(PGetCPrefs
);
4695 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4696 return EIO
; /* Inappropriate ioctl for device */
4698 spin
= afs_pd_inline(ain
, sizeof(*spin
));
4702 /* Output spout relies on writing past the end of arrays. It's horrible,
4703 * but I'm not quite brave enough to tackle it yet */
4704 spout
= (struct sprefinfo
*)aout
->ptr
;
4706 maxNumber
= spin
->num_servers
; /* max addrs this time */
4707 srvout
= spout
->servers
;
4709 ObtainReadLock(&afs_xinterface
);
4711 /* copy out the client interface information from the
4712 * kernel data structure "interface" to the output buffer
4714 for (i
= spin
->offset
, j
= 0; (i
< afs_cb_interface
.numberOfInterfaces
)
4715 && (j
< maxNumber
); i
++, j
++, srvout
++)
4716 srvout
->host
.s_addr
= afs_cb_interface
.addr_in
[i
];
4718 spout
->num_servers
= j
;
4719 aout
->ptr
+= sizeof(struct sprefinfo
) + (j
- 1) * sizeof(struct spref
);
4721 if (i
>= afs_cb_interface
.numberOfInterfaces
)
4722 spout
->next_offset
= 0; /* start from beginning again */
4724 spout
->next_offset
= spin
->offset
+ j
;
4726 ReleaseReadLock(&afs_xinterface
);
4731 * VIOC_SETCPREFS (51) - Set client interface
4735 * \param[in] ain the interfaces you want set
4736 * \param[out] aout not in use
4738 * \retval EIO Error if the afs daemon hasn't started yet
4739 * \retval EINVAL Error if the input is too large for the struct
4740 * \retval ENOMEM Error if there are too many servers
4742 * \post set the callbak interfaces addresses to those of the hosts
4744 DECL_PIOCTL(PSetCPrefs
)
4748 struct setspref
*sin
;
4751 AFS_STATCNT(PSetCPrefs
);
4752 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4753 return EIO
; /* Inappropriate ioctl for device */
4755 /* Yuck. Input to this function relies on reading past the end of
4756 * structures. Bodge it for now.
4759 ainSize
= ain
->remaining
;
4761 sin
= (struct setspref
*)ainPtr
;
4763 if (ainSize
< sizeof(struct setspref
))
4765 #if 0 /* num_servers is unsigned */
4766 if (sin
->num_servers
< 0)
4769 if (sin
->num_servers
> AFS_MAX_INTERFACE_ADDR
)
4772 ObtainWriteLock(&afs_xinterface
, 412);
4773 afs_cb_interface
.numberOfInterfaces
= sin
->num_servers
;
4774 for (i
= 0; (unsigned short)i
< sin
->num_servers
; i
++)
4775 afs_cb_interface
.addr_in
[i
] = sin
->servers
[i
].host
.s_addr
;
4777 ReleaseWriteLock(&afs_xinterface
);
4782 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4787 * the last part of a path to a mount point, which tells us what to flush
4792 * Error if some of the initial arguments aren't set
4794 * Error if the initial argument for the mount point isn't a directory
4796 * Error if the dcache entry isn't set
4799 * remove all of the mount data from the dcache regarding a
4800 * certain mount point
4802 DECL_PIOCTL(PFlushMount
)
4807 struct VenusFid tfid
;
4810 struct sysname_info sysState
;
4811 afs_size_t offset
, len
;
4813 AFS_STATCNT(PFlushMount
);
4817 if (afs_pd_getStringPtr(ain
, &mount
) != 0)
4820 code
= afs_VerifyVCache(avc
, areq
);
4823 if (vType(avc
) != VDIR
) {
4826 tdc
= afs_GetDCache(avc
, (afs_size_t
) 0, areq
, &offset
, &len
, 1);
4829 Check_AtSys(avc
, mount
, &sysState
, areq
);
4830 ObtainReadLock(&tdc
->lock
);
4832 code
= afs_dir_Lookup(tdc
, sysState
.name
, &tfid
.Fid
);
4833 } while (code
== ENOENT
&& Next_AtSys(avc
, areq
, &sysState
));
4834 ReleaseReadLock(&tdc
->lock
);
4835 afs_PutDCache(tdc
); /* we're done with the data */
4836 bufp
= sysState
.name
;
4840 tfid
.Cell
= avc
->f
.fid
.Cell
;
4841 tfid
.Fid
.Volume
= avc
->f
.fid
.Fid
.Volume
;
4842 if (!tfid
.Fid
.Unique
&& (avc
->f
.states
& CForeign
)) {
4843 tvc
= afs_LookupVCache(&tfid
, areq
, NULL
, avc
, bufp
);
4845 tvc
= afs_GetVCache(&tfid
, areq
, NULL
, NULL
);
4851 if (tvc
->mvstat
!= AFS_MVSTAT_MTPT
) {
4856 ObtainWriteLock(&tvc
->lock
, 649);
4857 /* next reference will re-stat cache entry */
4858 afs_StaleVCacheFlags(tvc
, 0, CDirty
);
4859 /* now find the disk cache entries */
4860 afs_TryToSmush(tvc
, *acred
, 1);
4861 if (tvc
->linkData
&& !(tvc
->f
.states
& CCore
)) {
4862 afs_osi_Free(tvc
->linkData
, strlen(tvc
->linkData
) + 1);
4863 tvc
->linkData
= NULL
;
4865 ReleaseWriteLock(&tvc
->lock
);
4868 if (sysState
.allocked
)
4869 osi_FreeLargeSpace(bufp
);
4874 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4878 * \param[in] ain the flags that control which stats to use
4879 * \param[out] aout not in use
4881 * \retval EACCES Error if the user doesn't have super-user credentials
4882 * \retval EINVAL Error if the flag input is too long
4885 * either enable process RPCStats, disable process RPCStats,
4886 * or clear the process RPCStats
4888 DECL_PIOCTL(PRxStatProc
)
4892 if (!afs_osi_suser(*acred
))
4895 if (afs_pd_getInt(ain
, &flags
) != 0)
4898 if (!(flags
& AFSCALL_RXSTATS_MASK
) || (flags
& ~AFSCALL_RXSTATS_MASK
))
4901 if (flags
& AFSCALL_RXSTATS_ENABLE
) {
4902 rx_enableProcessRPCStats();
4904 if (flags
& AFSCALL_RXSTATS_DISABLE
) {
4905 rx_disableProcessRPCStats();
4907 if (flags
& AFSCALL_RXSTATS_CLEAR
) {
4908 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL
);
4915 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4919 * \param[in] ain the flags that control which statistics to use
4920 * \param[out] aout not in use
4922 * \retval EACCES Error if the user doesn't have super-user credentials
4923 * \retval EINVAL Error if the flag input is too long
4926 * either enable peer RPCStatws, disable peer RPCStats,
4927 * or clear the peer RPCStats
4929 DECL_PIOCTL(PRxStatPeer
)
4933 if (!afs_osi_suser(*acred
))
4936 if (afs_pd_getInt(ain
, &flags
) != 0)
4939 if (!(flags
& AFSCALL_RXSTATS_MASK
) || (flags
& ~AFSCALL_RXSTATS_MASK
))
4942 if (flags
& AFSCALL_RXSTATS_ENABLE
) {
4943 rx_enablePeerRPCStats();
4945 if (flags
& AFSCALL_RXSTATS_DISABLE
) {
4946 rx_disablePeerRPCStats();
4948 if (flags
& AFSCALL_RXSTATS_CLEAR
) {
4949 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL
);
4954 DECL_PIOCTL(PPrefetchFromTape
)
4958 struct afs_conn
*tc
;
4959 struct rx_call
*tcall
;
4960 struct AFSVolSync tsync
;
4961 struct AFSFetchStatus OutStatus
;
4962 struct AFSCallBack CallBack
;
4963 struct VenusFid tfid
;
4966 struct rx_connection
*rxconn
;
4968 AFS_STATCNT(PPrefetchFromTape
);
4972 Fid
= afs_pd_inline(ain
, sizeof(struct AFSFid
));
4974 Fid
= &avc
->f
.fid
.Fid
;
4976 tfid
.Cell
= avc
->f
.fid
.Cell
;
4977 tfid
.Fid
.Volume
= Fid
->Volume
;
4978 tfid
.Fid
.Vnode
= Fid
->Vnode
;
4979 tfid
.Fid
.Unique
= Fid
->Unique
;
4981 tvc
= afs_GetVCache(&tfid
, areq
, NULL
, NULL
);
4983 afs_Trace3(afs_iclSetp
, CM_TRACE_PREFETCHCMD
, ICL_TYPE_POINTER
, tvc
,
4984 ICL_TYPE_FID
, &tfid
, ICL_TYPE_FID
, &avc
->f
.fid
);
4987 afs_Trace3(afs_iclSetp
, CM_TRACE_PREFETCHCMD
, ICL_TYPE_POINTER
, tvc
,
4988 ICL_TYPE_FID
, &tfid
, ICL_TYPE_FID
, &tvc
->f
.fid
);
4991 tc
= afs_Conn(&tvc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
4995 tcall
= rx_NewCall(rxconn
);
4997 StartRXAFS_FetchData(tcall
, (struct AFSFid
*)&tvc
->f
.fid
.Fid
, 0,
5000 rx_Read(tcall
, (char *)&outval
, sizeof(afs_int32
));
5002 EndRXAFS_FetchData(tcall
, &OutStatus
, &CallBack
, &tsync
);
5004 code
= rx_EndCall(tcall
, code
);
5008 } while (afs_Analyze
5009 (tc
, rxconn
, code
, &tvc
->f
.fid
, areq
, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS
,
5010 SHARED_LOCK
, NULL
));
5011 /* This call is done only to have the callback things handled correctly */
5012 afs_FetchStatus(tvc
, &tfid
, areq
, &OutStatus
);
5018 return afs_pd_putInt(aout
, outval
);
5024 struct afs_conn
*tc
;
5026 struct FsCmdInputs
*Inputs
;
5027 struct FsCmdOutputs
*Outputs
;
5028 struct VenusFid tfid
;
5030 struct rx_connection
*rxconn
;
5035 Inputs
= afs_pd_inline(ain
, sizeof(*Inputs
));
5039 Outputs
= afs_pd_inline(aout
, sizeof(*Outputs
));
5040 if (Outputs
== NULL
)
5045 Fid
= &avc
->f
.fid
.Fid
;
5047 tfid
.Cell
= avc
->f
.fid
.Cell
;
5048 tfid
.Fid
.Volume
= Fid
->Volume
;
5049 tfid
.Fid
.Vnode
= Fid
->Vnode
;
5050 tfid
.Fid
.Unique
= Fid
->Unique
;
5052 tvc
= afs_GetVCache(&tfid
, areq
, NULL
, NULL
);
5053 afs_Trace3(afs_iclSetp
, CM_TRACE_RESIDCMD
, ICL_TYPE_POINTER
, tvc
,
5054 ICL_TYPE_INT32
, Inputs
->command
, ICL_TYPE_FID
, &tfid
);
5058 if (Inputs
->command
) {
5060 tc
= afs_Conn(&tvc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
5064 RXAFS_FsCmd(rxconn
, Fid
, Inputs
, Outputs
);
5068 } while (afs_Analyze
5069 (tc
, rxconn
, code
, &tvc
->f
.fid
, areq
,
5070 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS
, SHARED_LOCK
, NULL
));
5071 /* This call is done to have the callback things handled correctly */
5072 afs_FetchStatus(tvc
, &tfid
, areq
, &Outputs
->status
);
5073 } else { /* just a status request, return also link data */
5075 Outputs
->code
= afs_FetchStatus(tvc
, &tfid
, areq
, &Outputs
->status
);
5076 Outputs
->chars
[0] = 0;
5077 if (vType(tvc
) == VLNK
) {
5078 ObtainWriteLock(&tvc
->lock
, 555);
5079 if (afs_HandleLink(tvc
, areq
) == 0)
5080 strncpy((char *)&Outputs
->chars
, tvc
->linkData
, MAXCMDCHARS
);
5081 ReleaseWriteLock(&tvc
->lock
);
5090 DECL_PIOCTL(PNewUuid
)
5092 /*AFS_STATCNT(PNewUuid); */
5093 if (!afs_resourceinit_flag
) /* afs deamons havn't started yet */
5094 return EIO
; /* Inappropriate ioctl for device */
5096 if (!afs_osi_suser(*acred
))
5099 ObtainWriteLock(&afs_xinterface
, 555);
5100 afs_uuid_create(&afs_cb_interface
.uuid
);
5101 ReleaseWriteLock(&afs_xinterface
);
5102 ForceAllNewConnections();
5106 #if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
5108 DECL_PIOCTL(PSetCachingThreshold
)
5110 afs_int32 getting
= 1;
5111 afs_int32 setting
= 1;
5112 afs_int32 threshold
= AFS_CACHE_BYPASS_DISABLED
;
5114 if (afs_pd_getInt(ain
, &threshold
) != 0)
5120 if (setting
== 0 && getting
== 0)
5124 * If setting, set first, and return the value now in effect
5127 if (!afs_osi_suser(*acred
))
5129 cache_bypass_threshold
= threshold
;
5130 afs_warn("Cache Bypass Threshold set to: %d\n", threshold
);
5131 /* TODO: move to separate pioctl, or enhance pioctl */
5132 if (threshold
== AFS_CACHE_BYPASS_DISABLED
)
5133 cache_bypass_strategy
= NEVER_BYPASS_CACHE
;
5134 else if (!threshold
)
5135 cache_bypass_strategy
= ALWAYS_BYPASS_CACHE
;
5137 cache_bypass_strategy
= LARGE_FILES_BYPASS_CACHE
;
5140 /* Return the current size threshold */
5142 return afs_pd_putInt(aout
, cache_bypass_threshold
);
5147 #endif /* defined(AFS_CACHE_BYPASS) */
5149 DECL_PIOCTL(PCallBackAddr
)
5152 afs_uint32 addr
, code
;
5156 struct afs_conn
*tc
;
5158 struct unixuser
*tu
;
5159 struct srvAddr
**addrs
;
5160 struct rx_connection
*rxconn
;
5162 /*AFS_STATCNT(PCallBackAddr); */
5163 if (!afs_resourceinit_flag
) /* afs deamons havn't started yet */
5164 return EIO
; /* Inappropriate ioctl for device */
5166 if (!afs_osi_suser(acred
))
5169 if (afs_pd_getInt(ain
, &addr
) != 0)
5172 ObtainReadLock(&afs_xinterface
);
5173 for (i
= 0; (unsigned short)i
< afs_cb_interface
.numberOfInterfaces
; i
++) {
5174 if (afs_cb_interface
.addr_in
[i
] == addr
)
5178 ReleaseWriteLock(&afs_xinterface
);
5180 if (afs_cb_interface
.addr_in
[i
] != addr
)
5183 ObtainReadLock(&afs_xserver
); /* Necessary? */
5184 ObtainReadLock(&afs_xsrvAddr
);
5187 for (i
= 0; i
< NSERVERS
; i
++) {
5188 for (sa
= afs_srvAddrs
[i
]; sa
; sa
= sa
->next_bkt
) {
5193 addrs
= afs_osi_Alloc(srvAddrCount
* sizeof(*addrs
));
5194 osi_Assert(addrs
!= NULL
);
5196 for (i
= 0; i
< NSERVERS
; i
++) {
5197 for (sa
= afs_srvAddrs
[i
]; sa
; sa
= sa
->next_bkt
) {
5198 if (j
>= srvAddrCount
)
5204 ReleaseReadLock(&afs_xsrvAddr
);
5205 ReleaseReadLock(&afs_xserver
);
5207 for (i
= 0; i
< j
; i
++) {
5213 /* vlserver has no callback conn */
5214 if (sa
->sa_portal
== AFS_VLPORT
) {
5218 if (!ts
->cell
) /* not really an active server, anyway, it must */
5219 continue; /* have just been added by setsprefs */
5221 /* get a connection, even if host is down; bumps conn ref count */
5222 tu
= afs_GetUser(areq
->uid
, ts
->cell
->cellNum
, SHARED_LOCK
);
5223 tc
= afs_ConnBySA(sa
, ts
->cell
->fsport
, ts
->cell
->cellNum
, tu
,
5224 1 /*force */ , 1 /*create */ , SHARED_LOCK
, 0, &rxconn
);
5225 afs_PutUser(tu
, SHARED_LOCK
);
5229 if ((sa
->sa_flags
& SRVADDR_ISDOWN
) || afs_HaveCallBacksFrom(ts
)) {
5230 if (sa
->sa_flags
& SRVADDR_ISDOWN
) {
5231 rx_SetConnDeadTime(rxconn
, 3);
5233 #ifdef RX_ENABLE_LOCKS
5235 #endif /* RX_ENABLE_LOCKS */
5236 code
= RXAFS_CallBackRxConnAddr(rxconn
, &addr
);
5237 #ifdef RX_ENABLE_LOCKS
5239 #endif /* RX_ENABLE_LOCKS */
5241 afs_PutConn(tc
, rxconn
, SHARED_LOCK
); /* done with it now */
5242 } /* Outer loop over addrs */
5243 #endif /* UKERNEL */
5247 DECL_PIOCTL(PDiscon
)
5249 static afs_int32 mode
= 1; /* Start up in 'off' */
5250 afs_int32 force
= 0;
5253 struct vrequest lreq
;
5255 if (afs_pd_getBytes(ain
, &flags
, 4) == 0) {
5256 if (!afs_osi_suser(*acred
))
5260 mode
= flags
[0] - 1;
5262 afs_ConflictPolicy
= flags
[1] - 1;
5266 /* Fake InitReq support for UID override */
5267 memset(&lreq
, 0, sizeof(lreq
));
5268 lreq
.uid
= flags
[3];
5269 areq
= &lreq
; /* override areq we got */
5273 * All of these numbers are hard coded in fs.c. If they
5274 * change here, they should change there and vice versa
5277 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
5278 if (!AFS_IS_DISCONNECTED
) {
5279 ObtainWriteLock(&afs_discon_lock
, 999);
5280 afs_DisconGiveUpCallbacks();
5281 afs_RemoveAllConns();
5282 afs_is_disconnected
= 1;
5283 afs_is_discon_rw
= 1;
5284 ReleaseWriteLock(&afs_discon_lock
);
5287 case 1: /* Fully connected, ("online" mode). */
5288 ObtainWriteLock(&afs_discon_lock
, 998);
5291 afs_MarkAllServersUp();
5292 code
= afs_ResyncDisconFiles(areq
, *acred
);
5295 if (code
&& !force
) {
5296 afs_warnuser("Files not synchronized properly, still in discon state. \n"
5297 "Please retry or use \"force\".\n");
5301 afs_DisconDiscardAll(*acred
);
5303 afs_ClearAllStatdFlag();
5304 afs_is_disconnected
= 0;
5305 afs_is_discon_rw
= 0;
5306 afs_warnuser("\nSync succeeded. You are back online.\n");
5309 ReleaseWriteLock(&afs_discon_lock
);
5321 return afs_pd_putInt(aout
, mode
);
5324 #define MAX_PIOCTL_TOKENS 10
5326 DECL_PIOCTL(PSetTokens2
)
5329 int i
, cellNum
, primaryFlag
;
5331 struct unixuser
*tu
;
5332 struct vrequest
*treq
= NULL
;
5333 struct ktc_setTokenData tokenSet
;
5334 struct ktc_tokenUnion decodedToken
;
5336 memset(&tokenSet
, 0, sizeof(tokenSet
));
5338 AFS_STATCNT(PSetTokens2
);
5339 if (!afs_resourceinit_flag
)
5342 afs_pd_xdrStart(ain
, &xdrs
, XDR_DECODE
);
5344 if (!xdr_ktc_setTokenData(&xdrs
, &tokenSet
)) {
5345 afs_pd_xdrEnd(ain
, &xdrs
);
5349 afs_pd_xdrEnd(ain
, &xdrs
);
5351 /* We limit each PAG to 10 tokens to prevent a malicous (or runaway)
5352 * process from using up the whole of the kernel memory by allocating
5355 if (tokenSet
.tokens
.tokens_len
> MAX_PIOCTL_TOKENS
) {
5356 xdr_free((xdrproc_t
) xdr_ktc_setTokenData
, &tokenSet
);
5360 code
= _settok_tokenCell(tokenSet
.cell
, &cellNum
, &primaryFlag
);
5362 xdr_free((xdrproc_t
) xdr_ktc_setTokenData
, &tokenSet
);
5366 if (tokenSet
.flags
& AFSTOKEN_EX_SETPAG
) {
5367 #if defined(AFS_LINUX26_ENV)
5368 afs_ucred_t
*old_cred
= *acred
;
5370 if (_settok_setParentPag(acred
) == 0) {
5371 #if defined(AFS_LINUX26_ENV)
5372 /* setpag() may have changed our credentials */
5376 code
= afs_CreateReq(&treq
, *acred
);
5378 xdr_free((xdrproc_t
) xdr_ktc_setTokenData
, &tokenSet
);
5385 tu
= afs_GetUser(areq
->uid
, cellNum
, WRITE_LOCK
);
5386 /* Free any tokens that we've already got */
5387 afs_FreeTokens(&tu
->tokens
);
5389 /* Iterate across the set of tokens we've received, and stuff them
5390 * into this user's tokenJar
5392 for (i
=0; i
< tokenSet
.tokens
.tokens_len
; i
++) {
5393 xdrmem_create(&xdrs
,
5394 tokenSet
.tokens
.tokens_val
[i
].token_opaque_val
,
5395 tokenSet
.tokens
.tokens_val
[i
].token_opaque_len
,
5398 memset(&decodedToken
, 0, sizeof(decodedToken
));
5399 if (!xdr_ktc_tokenUnion(&xdrs
, &decodedToken
)) {
5407 afs_AddTokenFromPioctl(&tu
->tokens
, &decodedToken
);
5408 /* This is untidy - the old token interface supported passing
5409 * the primaryFlag as part of the token interface. Current
5410 * OpenAFS userland never sets this, but it's specified as being
5411 * part of the XG interface, so we should probably still support
5412 * it. Rather than add it to our AddToken interface, just handle
5415 if (decodedToken
.at_type
== AFSTOKEN_UNION_KAD
) {
5416 if (decodedToken
.ktc_tokenUnion_u
.at_kad
.rk_primary_flag
)
5420 /* XXX - We should think more about destruction here. It's likely that
5421 * there is key material in what we're about to throw away, which
5422 * we really should zero out before giving back to the allocator */
5423 xdr_free((xdrproc_t
) xdr_ktc_tokenUnion
, &decodedToken
);
5426 tu
->states
|= UHasTokens
;
5427 tu
->states
&= ~UTokensBad
;
5428 afs_SetPrimary(tu
, primaryFlag
);
5429 tu
->tokenTime
= osi_Time();
5431 xdr_free((xdrproc_t
) xdr_ktc_setTokenData
, &tokenSet
);
5434 afs_ResetUserConns(tu
);
5435 afs_PutUser(tu
, WRITE_LOCK
);
5436 afs_DestroyReq(treq
);
5441 DECL_PIOCTL(PGetTokens2
)
5443 struct cell
*cell
= NULL
;
5444 struct unixuser
*tu
= NULL
;
5446 char *cellName
= NULL
;
5451 struct ktc_setTokenData tokenSet
;
5453 AFS_STATCNT(PGetTokens
);
5454 if (!afs_resourceinit_flag
)
5457 memset(&tokenSet
, 0, sizeof(tokenSet
));
5459 /* No input data - return tokens for primary cell */
5460 /* 4 octets of data is an iterator count */
5461 /* Otherwise, treat as string & return tokens for that cell name */
5463 if (afs_pd_remaining(ain
) == sizeof(afs_int32
)) {
5464 /* Integer iterator - return tokens for the n'th cell found for user */
5465 if (afs_pd_getInt(ain
, &iterator
) != 0)
5467 tu
= getNthCell(areq
->uid
, iterator
);
5469 if (afs_pd_remaining(ain
) > 0) {
5470 if (afs_pd_getStringPtr(ain
, &cellName
) != 0)
5475 code
= _settok_tokenCell(cellName
, &cellNum
, NULL
);
5478 tu
= afs_FindUser(areq
->uid
, cellNum
, READ_LOCK
);
5485 if (!(tu
->states
& UHasTokens
)
5486 || !afs_HasValidTokens(tu
->tokens
, now
)) {
5487 tu
->states
|= (UTokensBad
| UNeedsReset
);
5488 afs_PutUser(tu
, READ_LOCK
);
5492 code
= afs_ExtractTokensForPioctl(tu
->tokens
, now
, &tokenSet
);
5496 cell
= afs_GetCell(tu
->cell
, READ_LOCK
);
5497 tokenSet
.cell
= cell
->cellName
;
5498 afs_pd_xdrStart(aout
, &xdrs
, XDR_ENCODE
);
5499 if (!xdr_ktc_setTokenData(&xdrs
, &tokenSet
)) {
5503 afs_pd_xdrEnd(aout
, &xdrs
);
5506 tokenSet
.cell
= NULL
;
5509 afs_PutUser(tu
, READ_LOCK
);
5511 afs_PutCell(cell
, READ_LOCK
);
5512 xdr_free((xdrproc_t
)xdr_ktc_setTokenData
, &tokenSet
);
5517 DECL_PIOCTL(PNFSNukeCreds
)
5521 struct unixuser
*tu
;
5523 AFS_STATCNT(PUnlog
);
5524 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
5525 return EIO
; /* Inappropriate ioctl for device */
5527 if (afs_pd_getUint(ain
, &addr
) != 0)
5530 if (afs_cr_gid(*acred
) == RMTUSER_REQ_PRIV
&& !addr
) {
5531 tu
= afs_GetUser(areq
->uid
, -1, SHARED_LOCK
);
5532 if (!tu
->exporter
|| !(addr
= EXP_GETHOST(tu
->exporter
))) {
5533 afs_PutUser(tu
, SHARED_LOCK
);
5536 afs_PutUser(tu
, SHARED_LOCK
);
5537 } else if (!afs_osi_suser(acred
)) {
5541 ObtainWriteLock(&afs_xuser
, 227);
5542 for (i
= 0; i
< NUSERS
; i
++) {
5543 for (tu
= afs_users
[i
]; tu
; tu
= tu
->next
) {
5544 if (tu
->exporter
&& EXP_CHECKHOST(tu
->exporter
, addr
)) {
5546 ReleaseWriteLock(&afs_xuser
);
5548 afs_LockUser(tu
, WRITE_LOCK
, 367);
5550 tu
->states
&= ~UHasTokens
;
5551 afs_FreeTokens(&tu
->tokens
);
5552 afs_ResetUserConns(tu
);
5553 afs_PutUser(tu
, WRITE_LOCK
);
5554 ObtainWriteLock(&afs_xuser
, 228);
5556 /* set the expire times to 0, causes
5557 * afs_GCUserData to remove this entry
5560 #endif /* UKERNEL */
5564 ReleaseWriteLock(&afs_xuser
);