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
;
2277 if (iterator
> afs_cellindex
)
2278 return NULL
; /* no point in looking */
2281 ObtainReadLock(&afs_xuser
);
2282 for (tu
= afs_users
[i
]; tu
; tu
= tu
->next
) {
2283 if (tu
->uid
== uid
&& (tu
->states
& UHasTokens
)) {
2284 if (iterator
-- == 0)
2285 break; /* are we done yet? */
2291 ReleaseReadLock(&afs_xuser
);
2293 afs_LockUser(tu
, READ_LOCK
, 0);
2300 * VIOCGETTOK (8) - Get authentication tokens
2304 * \param[in] ain cellid to return tokens for
2305 * \param[out] aout token
2308 * Error if the afs daemon hasn't started yet
2310 * Error if the input parameter is out of the bounds of the available
2313 * Error if there aren't tokens for this cell
2316 * If the input paramater exists, get the token that corresponds to
2317 * the parameter value, if there is no token at this value, get the
2318 * token for the first cell
2320 * \notes "it's a weird interface (from comments in the code)"
2323 DECL_PIOCTL(PGetTokens
)
2326 struct unixuser
*tu
= NULL
;
2327 union tokenUnion
*token
;
2328 afs_int32 iterator
= 0;
2333 AFS_STATCNT(PGetTokens
);
2334 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2335 return EIO
; /* Inappropriate ioctl for device */
2337 /* weird interface. If input parameter is present, it is an integer and
2338 * we're supposed to return the parm'th tokens for this unix uid.
2339 * If not present, we just return tokens for cell 1.
2340 * If counter out of bounds, return EDOM.
2341 * If no tokens for the particular cell, return ENOTCONN.
2342 * Also, if this mysterious parm is present, we return, along with the
2343 * tokens, the primary cell indicator (an afs_int32 0) and the cell name
2344 * at the end, in that order.
2346 newStyle
= (afs_pd_remaining(ain
) > 0);
2348 if (afs_pd_getInt(ain
, &iterator
) != 0)
2352 tu
= getNthCell(areq
->uid
, iterator
);
2354 cellNum
= afs_GetPrimaryCellNum();
2356 tu
= afs_FindUser(areq
->uid
, cellNum
, READ_LOCK
);
2361 if (!(tu
->states
& UHasTokens
)
2362 || !afs_HasUsableTokens(tu
->tokens
, osi_Time())) {
2363 tu
->states
|= (UTokensBad
| UNeedsReset
);
2364 afs_NotifyUser(tu
, UTokensDropped
);
2365 afs_PutUser(tu
, READ_LOCK
);
2368 token
= afs_FindToken(tu
->tokens
, RX_SECIDX_KAD
);
2370 /* If they don't have an RXKAD token, but do have other tokens,
2371 * then sadly there's nothing this interface can do to help them. */
2375 /* for compat, we try to return 56 byte tix if they fit */
2376 iterator
= token
->rxkad
.ticketLen
;
2378 iterator
= 56; /* # of bytes we're returning */
2380 if (afs_pd_putInt(aout
, iterator
) != 0)
2382 if (afs_pd_putBytes(aout
, token
->rxkad
.ticket
, token
->rxkad
.ticketLen
) != 0)
2384 if (token
->rxkad
.ticketLen
< 56) {
2385 /* Tokens are always 56 bytes or larger */
2386 if (afs_pd_skip(aout
, iterator
- token
->rxkad
.ticketLen
) != 0) {
2391 if (afs_pd_putInt(aout
, sizeof(struct ClearToken
)) != 0)
2393 if (afs_pd_putBytes(aout
, &token
->rxkad
.clearToken
,
2394 sizeof(struct ClearToken
)) != 0)
2398 /* put out primary id and cell name, too */
2399 iterator
= (tu
->states
& UPrimary
? 1 : 0);
2400 if (afs_pd_putInt(aout
, iterator
) != 0)
2402 tcell
= afs_GetCell(tu
->cell
, READ_LOCK
);
2404 if (afs_pd_putString(aout
, tcell
->cellName
) != 0)
2406 afs_PutCell(tcell
, READ_LOCK
);
2408 if (afs_pd_putString(aout
, "") != 0)
2411 /* Got here, all is good */
2414 afs_PutUser(tu
, READ_LOCK
);
2419 * VIOCUNLOG (9) - Invalidate tokens
2423 * \param[in] ain not in use
2424 * \param[out] aout not in use
2426 * \retval EIO Error if the afs daemon hasn't been started yet
2428 * \post remove tokens from a user, specified by the user id
2430 * \notes sets the token's time to 0, which then causes it to be removed
2431 * \notes Unlog is the same as un-pag in OpenAFS
2436 struct unixuser
*tu
;
2438 AFS_STATCNT(PUnlog
);
2439 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2440 return EIO
; /* Inappropriate ioctl for device */
2442 i
= UHash(areq
->uid
);
2443 ObtainWriteLock(&afs_xuser
, 227);
2444 for (tu
= afs_users
[i
]; tu
; tu
= tu
->next
) {
2445 if (tu
->uid
== areq
->uid
) {
2447 ReleaseWriteLock(&afs_xuser
);
2449 afs_LockUser(tu
, WRITE_LOCK
, 366);
2451 tu
->states
&= ~UHasTokens
;
2452 afs_FreeTokens(&tu
->tokens
);
2453 afs_NotifyUser(tu
, UTokensDropped
);
2454 /* We have to drop the lock over the call to afs_ResetUserConns,
2455 * since it obtains the afs_xvcache lock. We could also keep
2456 * the lock, and modify ResetUserConns to take parm saying we
2457 * obtained the lock already, but that is overkill. By keeping
2458 * the "tu" pointer held over the released lock, we guarantee
2459 * that we won't lose our place, and that we'll pass over
2460 * every user conn that existed when we began this call.
2462 afs_ResetUserConns(tu
);
2463 afs_PutUser(tu
, WRITE_LOCK
);
2464 ObtainWriteLock(&afs_xuser
, 228);
2466 /* set the expire times to 0, causes
2467 * afs_GCUserData to remove this entry
2470 #endif /* UKERNEL */
2473 ReleaseWriteLock(&afs_xuser
);
2478 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
2482 * \param[in] ain host address to be set
2483 * \param[out] aout old host address
2486 * depending on whether or not a variable is set, either get the host
2487 * for the cache manager monitor, or set the old address and give it
2490 * \notes Errors turn off mariner
2492 DECL_PIOCTL(PMariner
)
2494 afs_int32 newHostAddr
;
2495 afs_int32 oldHostAddr
;
2497 AFS_STATCNT(PMariner
);
2499 memcpy((char *)&oldHostAddr
, (char *)&afs_marinerHost
,
2502 oldHostAddr
= 0xffffffff; /* disabled */
2504 if (afs_pd_getInt(ain
, &newHostAddr
) != 0)
2507 if (newHostAddr
== 0xffffffff) {
2508 /* disable mariner operations */
2510 } else if (newHostAddr
) {
2512 afs_marinerHost
= newHostAddr
;
2515 if (afs_pd_putInt(aout
, oldHostAddr
) != 0)
2522 * VIOCCKSERV (10) - Check that servers are up
2526 * \param[in] ain name of the cell
2527 * \param[out] aout current down server list
2529 * \retval EIO Error if the afs daemon hasn't started yet
2530 * \retval EACCES Error if the user doesn't have super-user credentials
2531 * \retval ENOENT Error if we are unable to obtain the cell
2534 * Either a fast check (where it doesn't contact servers) or a
2535 * local check (checks local cell only)
2537 DECL_PIOCTL(PCheckServers
)
2542 char *cellName
= NULL
;
2544 struct chservinfo
*pcheck
;
2546 AFS_STATCNT(PCheckServers
);
2548 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2549 return EIO
; /* Inappropriate ioctl for device */
2551 /* This is tricky, because we need to peak at the datastream to see
2552 * what we're getting. For now, let's cheat. */
2554 /* ain contains either an int32 or a string */
2555 if (ain
->remaining
== 0)
2558 if (*(afs_int32
*)ain
->ptr
== 0x12345678) { /* For afs3.3 version */
2559 pcheck
= afs_pd_inline(ain
, sizeof(*pcheck
));
2563 if (pcheck
->tinterval
>= 0) {
2564 if (afs_pd_putInt(aout
, afs_probe_interval
) != 0)
2566 if (pcheck
->tinterval
> 0) {
2567 if (!afs_osi_suser(*acred
))
2569 afs_probe_interval
= pcheck
->tinterval
;
2573 temp
= pcheck
->tflags
;
2575 cellName
= pcheck
->tbuffer
;
2576 } else { /* For pre afs3.3 versions */
2577 if (afs_pd_getInt(ain
, &temp
) != 0)
2579 if (afs_pd_remaining(ain
) > 0) {
2580 if (afs_pd_getStringPtr(ain
, &cellName
) != 0)
2586 * 1: fast check, don't contact servers.
2587 * 2: local cell only.
2590 /* have cell name, too */
2591 cellp
= afs_GetCellByName(cellName
, READ_LOCK
);
2596 if (!cellp
&& (temp
& 2)) {
2597 /* use local cell */
2598 cellp
= afs_GetPrimaryCell(READ_LOCK
);
2600 if (!(temp
& 1)) { /* if not fast, call server checker routine */
2601 afs_CheckServers(1, cellp
); /* check down servers */
2602 afs_CheckServers(0, cellp
); /* check up servers */
2604 /* now return the current down server list */
2605 ObtainReadLock(&afs_xserver
);
2606 for (i
= 0; i
< NSERVERS
; i
++) {
2607 for (ts
= afs_servers
[i
]; ts
; ts
= ts
->next
) {
2608 if (cellp
&& ts
->cell
!= cellp
)
2609 continue; /* cell spec'd and wrong */
2610 if ((ts
->flags
& SRVR_ISDOWN
)
2611 && ts
->addr
->sa_portal
!= ts
->cell
->vlport
) {
2612 afs_pd_putInt(aout
, ts
->addr
->sa_ip
);
2616 ReleaseReadLock(&afs_xserver
);
2618 afs_PutCell(cellp
, READ_LOCK
);
2623 * VIOCCKBACK (11) - Check backup volume mappings
2627 * \param[in] ain not in use
2628 * \param[out] aout not in use
2630 * \retval EIO Error if the afs daemon hasn't started yet
2633 * Check the root volume, and then check the names if the volume
2634 * check variable is set to force, has expired, is busy, or if
2635 * the mount points variable is set
2637 DECL_PIOCTL(PCheckVolNames
)
2639 AFS_STATCNT(PCheckVolNames
);
2640 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2641 return EIO
; /* Inappropriate ioctl for device */
2643 afs_CheckRootVolume();
2644 afs_CheckVolumeNames(AFS_VOLCHECK_FORCE
| AFS_VOLCHECK_EXPIRED
|
2645 AFS_VOLCHECK_BUSY
| AFS_VOLCHECK_MTPTS
);
2650 * VIOCCKCONN (12) - Check connections for a user
2654 * \param[in] ain not in use
2655 * \param[out] aout not in use
2658 * Error if no user is specififed, the user has no tokens set,
2659 * or if the user's tokens are bad
2662 * check to see if a user has the correct authentication.
2663 * If so, allow access.
2665 * \notes Check the connections to all the servers specified
2667 DECL_PIOCTL(PCheckAuth
)
2671 struct sa_conn_vector
*tcv
;
2672 struct unixuser
*tu
;
2675 AFS_STATCNT(PCheckAuth
);
2676 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
2677 return EIO
; /* Inappropriate ioctl for device */
2680 tu
= afs_GetUser(areq
->uid
, 1, READ_LOCK
); /* check local cell authentication */
2684 /* we have a user */
2685 ObtainReadLock(&afs_xsrvAddr
);
2686 ObtainReadLock(&afs_xconn
);
2688 /* any tokens set? */
2689 if ((tu
->states
& UHasTokens
) == 0)
2691 /* all connections in cell 1 working? */
2692 for (i
= 0; i
< NSERVERS
; i
++) {
2693 for (sa
= afs_srvAddrs
[i
]; sa
; sa
= sa
->next_bkt
) {
2694 for (tcv
= sa
->conns
; tcv
; tcv
= tcv
->next
) {
2695 if (tcv
->user
== tu
&& (tu
->states
& UTokensBad
))
2700 ReleaseReadLock(&afs_xsrvAddr
);
2701 ReleaseReadLock(&afs_xconn
);
2702 afs_PutUser(tu
, READ_LOCK
);
2704 if (afs_pd_putInt(aout
, retValue
) != 0)
2710 Prefetch(uparmtype apath
, struct afs_ioctl
*adata
, int afollow
,
2715 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
2721 AFS_STATCNT(Prefetch
);
2724 tp
= osi_AllocLargeSpace(1024);
2725 AFS_COPYINSTR(apath
, tp
, 1024, &bufferSize
, code
);
2727 osi_FreeLargeSpace(tp
);
2730 if (afs_BBusy()) { /* do this as late as possible */
2731 osi_FreeLargeSpace(tp
);
2732 return EWOULDBLOCK
; /* pretty close */
2734 afs_BQueue(BOP_PATH
, (struct vcache
*)0, 0, 0, acred
, (afs_size_t
) 0,
2735 (afs_size_t
) 0, tp
, (void *)0, (void *)0);
2740 * VIOCWHEREIS (14) - Find out where a volume is located
2744 * \param[in] ain not in use
2745 * \param[out] aout volume location
2747 * \retval EINVAL Error if some of the default arguments don't exist
2748 * \retval ENODEV Error if there is no such volume
2750 * \post fine a volume, based on a volume file id
2752 * \notes check each of the servers specified
2754 DECL_PIOCTL(PFindVolume
)
2761 AFS_STATCNT(PFindVolume
);
2764 tvp
= afs_GetVolume(&avc
->f
.fid
, areq
, READ_LOCK
);
2768 for (i
= 0; i
< AFS_MAXHOSTS
; i
++) {
2769 ts
= tvp
->serverHost
[i
];
2772 if (afs_pd_putInt(aout
, ts
->addr
->sa_ip
) != 0) {
2777 if (i
< AFS_MAXHOSTS
) {
2778 /* still room for terminating NULL, add it on */
2779 if (afs_pd_putInt(aout
, 0) != 0) {
2785 afs_PutVolume(tvp
, READ_LOCK
);
2790 * VIOCACCESS (20) - Access using PRS_FS bits
2794 * \param[in] ain PRS_FS bits
2795 * \param[out] aout not in use
2797 * \retval EINVAL Error if some of the initial arguments aren't set
2798 * \retval EACCES Error if access is denied
2800 * \post check to make sure access is allowed
2802 DECL_PIOCTL(PViceAccess
)
2807 AFS_STATCNT(PViceAccess
);
2811 code
= afs_VerifyVCache(avc
, areq
);
2815 if (afs_pd_getInt(ain
, &temp
) != 0)
2818 code
= afs_AccessOK(avc
, temp
, areq
, CHECK_MODE_BITS
);
2826 * VIOC_GETPAG (13) - Get PAG value
2830 * \param[in] ain not in use
2831 * \param[out] aout PAG value or NOPAG
2833 * \post get PAG value for the caller's cred
2835 DECL_PIOCTL(PGetPAG
)
2839 pag
= PagInCred(*acred
);
2841 return afs_pd_putInt(aout
, pag
);
2844 DECL_PIOCTL(PPrecache
)
2848 /*AFS_STATCNT(PPrecache);*/
2849 if (!afs_osi_suser(*acred
))
2852 if (afs_pd_getInt(ain
, &newValue
) != 0)
2855 afs_preCache
= newValue
*1024;
2860 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
2864 * \param[in] ain the size the venus cache should be set to
2865 * \param[out] aout not in use
2867 * \retval EACCES Error if the user doesn't have super-user credentials
2868 * \retval EROFS Error if the cache is set to be in memory
2871 * Set the cache size based on user input. If no size is given,
2872 * set it to the default OpenAFS cache size.
2875 * recompute the general cache parameters for every single block allocated
2877 DECL_PIOCTL(PSetCacheSize
)
2882 AFS_STATCNT(PSetCacheSize
);
2884 if (!afs_osi_suser(*acred
))
2886 /* too many things are setup initially in mem cache version */
2887 if (cacheDiskType
== AFS_FCACHE_TYPE_MEM
)
2889 if (afs_pd_getInt(ain
, &newValue
) != 0)
2892 afs_cacheBlocks
= afs_stats_cmperf
.cacheBlocksOrig
;
2894 if (newValue
< afs_min_cache
)
2895 afs_cacheBlocks
= afs_min_cache
;
2897 afs_cacheBlocks
= newValue
;
2899 afs_stats_cmperf
.cacheBlocksTotal
= afs_cacheBlocks
;
2900 afs_ComputeCacheParms(); /* recompute basic cache parameters */
2901 afs_MaybeWakeupTruncateDaemon();
2902 while (waitcnt
++ < 100 && afs_cacheBlocks
< afs_blocksUsed
) {
2903 afs_osi_Wait(1000, 0, 0);
2904 afs_MaybeWakeupTruncateDaemon();
2909 #define MAXGCSTATS 16
2911 * VIOCGETCACHEPARMS (40) - Get cache stats
2915 * \param[in] ain afs index flags
2916 * \param[out] aout cache blocks, blocks used, blocks files (in an array)
2918 * \post Get the cache blocks, and how many of the cache blocks there are
2920 DECL_PIOCTL(PGetCacheSize
)
2922 afs_int32 results
[MAXGCSTATS
];
2924 struct dcache
* tdc
;
2927 AFS_STATCNT(PGetCacheSize
);
2929 if (afs_pd_remaining(ain
) == sizeof(afs_int32
)) {
2930 afs_pd_getInt(ain
, &flags
); /* can't error, we just checked size */
2931 } else if (afs_pd_remaining(ain
) == 0) {
2937 memset(results
, 0, sizeof(results
));
2938 results
[0] = afs_cacheBlocks
;
2939 results
[1] = afs_blocksUsed
;
2940 results
[2] = afs_cacheFiles
;
2943 for (i
= 0; i
< afs_cacheFiles
; i
++) {
2944 if (afs_indexFlags
[i
] & IFFree
) results
[3]++;
2946 } else if (2 == flags
){
2947 for (i
= 0; i
< afs_cacheFiles
; i
++) {
2948 if (afs_indexFlags
[i
] & IFFree
) results
[3]++;
2949 if (afs_indexFlags
[i
] & IFEverUsed
) results
[4]++;
2950 if (afs_indexFlags
[i
] & IFDataMod
) results
[5]++;
2951 if (afs_indexFlags
[i
] & IFDirtyPages
) results
[6]++;
2952 if (afs_indexFlags
[i
] & IFAnyPages
) results
[7]++;
2953 if (afs_indexFlags
[i
] & IFDiscarded
) results
[8]++;
2955 tdc
= afs_indexTable
[i
];
2957 afs_size_t size
= tdc
->validPos
;
2960 if ( 0 <= size
&& size
< (1<<12) ) results
[10]++;
2961 else if (size
< (1<<14) ) results
[11]++;
2962 else if (size
< (1<<16) ) results
[12]++;
2963 else if (size
< (1<<18) ) results
[13]++;
2964 else if (size
< (1<<20) ) results
[14]++;
2965 else if (size
>= (1<<20) ) results
[15]++;
2969 return afs_pd_putBytes(aout
, results
, sizeof(results
));
2973 * VIOCFLUSHCB (25) - Flush callback only
2977 * \param[in] ain not in use
2978 * \param[out] aout not in use
2980 * \retval EINVAL Error if some of the standard args aren't set
2981 * \retval 0 0 returned if the volume is set to read-only
2984 * Flushes callbacks, by setting the length of callbacks to one,
2985 * setting the next callback to be sent to the CB_DROPPED value,
2986 * and then dequeues everything else.
2988 DECL_PIOCTL(PRemoveCallBack
)
2990 struct afs_conn
*tc
;
2992 struct AFSCallBack CallBacks_Array
[1];
2993 struct AFSCBFids theFids
;
2994 struct AFSCBs theCBs
;
2995 struct rx_connection
*rxconn
;
2998 AFS_STATCNT(PRemoveCallBack
);
3001 if (avc
->f
.states
& CRO
)
3002 return 0; /* read-only-ness can't change */
3003 ObtainWriteLock(&avc
->lock
, 229);
3004 theFids
.AFSCBFids_len
= 1;
3005 theCBs
.AFSCBs_len
= 1;
3006 theFids
.AFSCBFids_val
= (struct AFSFid
*)&avc
->f
.fid
.Fid
;
3007 theCBs
.AFSCBs_val
= CallBacks_Array
;
3008 CallBacks_Array
[0].CallBackType
= CB_DROPPED
;
3009 if (avc
->callback
) {
3011 tc
= afs_Conn(&avc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
3013 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS
);
3015 code
= RXAFS_GiveUpCallBacks(rxconn
, &theFids
, &theCBs
);
3019 /* don't set code on failure since we wouldn't use it */
3020 } while (afs_Analyze
3021 (tc
, rxconn
, code
, &avc
->f
.fid
, areq
,
3022 AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS
, SHARED_LOCK
, NULL
));
3024 afs_StaleVCacheFlags(avc
, AFS_STALEVC_CLEARCB
, CUnique
);
3026 ReleaseWriteLock(&avc
->lock
);
3031 * VIOCNEWCELL (26) - Configure new cell
3036 * the name of the cell, the hosts that will be a part of the cell,
3037 * whether or not it's linked with another cell, the other cell it's
3038 * linked with, the file server port, and the volume server port
3042 * \retval EIO Error if the afs daemon hasn't started yet
3043 * \retval EACCES Error if the user doesn't have super-user cedentials
3044 * \retval EINVAL Error if some 'magic' var doesn't have a certain bit set
3046 * \post creates a new cell
3048 DECL_PIOCTL(PNewCell
)
3050 afs_int32 cellHosts
[AFS_MAXCELLHOSTS
], magic
= 0;
3051 char *newcell
= NULL
;
3052 char *linkedcell
= NULL
;
3054 afs_int32 linkedstate
= 0;
3055 afs_int32 fsport
= 0, vlport
= 0;
3058 AFS_STATCNT(PNewCell
);
3059 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3060 return EIO
; /* Inappropriate ioctl for device */
3062 if (!afs_osi_suser(*acred
))
3065 if (afs_pd_getInt(ain
, &magic
) != 0)
3067 if (magic
!= 0x12345678)
3070 /* A 3.4 fs newcell command will pass an array of AFS_MAXCELLHOSTS
3071 * server addresses while the 3.5 fs newcell command passes
3072 * AFS_MAXHOSTS. To figure out which is which, check if the cellname
3075 * This whole logic is bogus, because it relies on the newer command
3076 * sending its 12th address as 0.
3078 if (afs_pd_remaining(ain
) < (AFS_MAXCELLHOSTS
+ 3) * sizeof(afs_int32
))
3081 newcell
= afs_pd_where(ain
) + (AFS_MAXCELLHOSTS
+ 3) * sizeof(afs_int32
);
3082 if (newcell
[0] != '\0') {
3085 skip
= AFS_MAXHOSTS
- AFS_MAXCELLHOSTS
;
3088 /* AFS_MAXCELLHOSTS (=8) is less than AFS_MAXHOSTS (=13) */
3089 if (afs_pd_getBytes(ain
, &cellHosts
,
3090 AFS_MAXCELLHOSTS
* sizeof(afs_int32
)) != 0)
3092 if (afs_pd_skip(ain
, skip
* sizeof(afs_int32
)) !=0)
3095 if (afs_pd_getInt(ain
, &fsport
) != 0)
3098 fsport
= 0; /* Privileged ports not allowed */
3100 if (afs_pd_getInt(ain
, &vlport
) != 0)
3103 vlport
= 0; /* Privileged ports not allowed */
3105 if (afs_pd_getInt(ain
, &ls
) != 0)
3108 if (afs_pd_getStringPtr(ain
, &newcell
) != 0)
3112 if (afs_pd_getStringPtr(ain
, &linkedcell
) != 0)
3114 linkedstate
|= CLinkedCell
;
3117 linkedstate
|= CNoSUID
; /* setuid is disabled by default for fs newcell */
3119 afs_NewCell(newcell
, cellHosts
, linkedstate
, linkedcell
, fsport
,
3124 DECL_PIOCTL(PNewAlias
)
3126 /* create a new cell alias */
3127 char *realName
, *aliasName
;
3129 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3130 return EIO
; /* Inappropriate ioctl for device */
3132 if (!afs_osi_suser(*acred
))
3135 if (afs_pd_getStringPtr(ain
, &aliasName
) != 0)
3137 if (afs_pd_getStringPtr(ain
, &realName
) != 0)
3140 return afs_NewCellAlias(aliasName
, realName
);
3144 * VIOCGETCELL (27) - Get cell info
3148 * \param[in] ain The cell index of a specific cell
3149 * \param[out] aout list of servers in the cell
3151 * \retval EIO Error if the afs daemon hasn't started yet
3152 * \retval EDOM Error if there is no cell asked about
3154 * \post Lists the cell's server names and and addresses
3156 DECL_PIOCTL(PListCells
)
3158 afs_int32 whichCell
;
3159 struct cell
*tcell
= 0;
3163 AFS_STATCNT(PListCells
);
3164 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3165 return EIO
; /* Inappropriate ioctl for device */
3167 if (afs_pd_getInt(ain
, &whichCell
) != 0)
3170 tcell
= afs_GetCellByIndex(whichCell
, READ_LOCK
);
3176 for (i
= 0; i
< AFS_MAXCELLHOSTS
; i
++) {
3177 if (tcell
->cellHosts
[i
] == 0)
3179 if (afs_pd_putInt(aout
, tcell
->cellHosts
[i
]->addr
->sa_ip
) != 0)
3182 for (;i
< AFS_MAXCELLHOSTS
; i
++) {
3183 if (afs_pd_putInt(aout
, 0) != 0)
3186 if (afs_pd_putString(aout
, tcell
->cellName
) != 0)
3191 afs_PutCell(tcell
, READ_LOCK
);
3195 DECL_PIOCTL(PListAliases
)
3197 afs_int32 whichAlias
;
3198 struct cell_alias
*tcalias
= 0;
3201 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3202 return EIO
; /* Inappropriate ioctl for device */
3204 if (afs_pd_getInt(ain
, &whichAlias
) != 0)
3207 tcalias
= afs_GetCellAlias(whichAlias
);
3208 if (tcalias
== NULL
)
3212 if (afs_pd_putString(aout
, tcalias
->alias
) != 0)
3214 if (afs_pd_putString(aout
, tcalias
->cell
) != 0)
3219 afs_PutCellAlias(tcalias
);
3224 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
3228 * \param[in] ain the name of the file in this dir to remove
3229 * \param[out] aout not in use
3232 * Error if some of the standard args aren't set
3234 * Error if the argument to remove is not a directory
3236 * Error if there is no cache to remove the mount point from or
3237 * if a vcache doesn't exist
3240 * Ensure that everything is OK before deleting the mountpoint.
3241 * If not, don't delete. Delete a mount point based on a file id.
3243 DECL_PIOCTL(PRemoveMount
)
3248 struct sysname_info sysState
;
3249 afs_size_t offset
, len
;
3250 struct afs_conn
*tc
;
3253 struct AFSFetchStatus OutDirStatus
;
3254 struct VenusFid tfid
;
3255 struct AFSVolSync tsync
;
3256 struct rx_connection
*rxconn
;
3259 /* "ain" is the name of the file in this dir to remove */
3261 AFS_STATCNT(PRemoveMount
);
3264 if (afs_pd_getStringPtr(ain
, &name
) != 0)
3267 code
= afs_VerifyVCache(avc
, areq
);
3270 if (vType(avc
) != VDIR
)
3273 tdc
= afs_GetDCache(avc
, (afs_size_t
) 0, areq
, &offset
, &len
, 1); /* test for error below */
3276 Check_AtSys(avc
, name
, &sysState
, areq
);
3277 ObtainReadLock(&tdc
->lock
);
3279 code
= afs_dir_Lookup(tdc
, sysState
.name
, &tfid
.Fid
);
3280 } while (code
== ENOENT
&& Next_AtSys(avc
, areq
, &sysState
));
3281 ReleaseReadLock(&tdc
->lock
);
3282 bufp
= sysState
.name
;
3287 tfid
.Cell
= avc
->f
.fid
.Cell
;
3288 tfid
.Fid
.Volume
= avc
->f
.fid
.Fid
.Volume
;
3289 if (!tfid
.Fid
.Unique
&& (avc
->f
.states
& CForeign
)) {
3290 tvc
= afs_LookupVCache(&tfid
, areq
, NULL
, avc
, bufp
);
3292 tvc
= afs_GetVCache(&tfid
, areq
, NULL
, NULL
);
3299 if (tvc
->mvstat
!= AFS_MVSTAT_MTPT
) {
3305 ObtainWriteLock(&tvc
->lock
, 230);
3306 code
= afs_HandleLink(tvc
, areq
);
3308 if (tvc
->linkData
) {
3309 if ((tvc
->linkData
[0] != '#') && (tvc
->linkData
[0] != '%'))
3314 ReleaseWriteLock(&tvc
->lock
);
3315 osi_dnlc_purgedp(tvc
);
3321 ObtainWriteLock(&avc
->lock
, 231);
3322 osi_dnlc_remove(avc
, bufp
, tvc
);
3324 tc
= afs_Conn(&avc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
3326 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE
);
3329 RXAFS_RemoveFile(rxconn
, (struct AFSFid
*)&avc
->f
.fid
.Fid
, bufp
,
3330 &OutDirStatus
, &tsync
);
3335 } while (afs_Analyze
3336 (tc
, rxconn
, code
, &avc
->f
.fid
, areq
, AFS_STATS_FS_RPCIDX_REMOVEFILE
,
3337 SHARED_LOCK
, NULL
));
3342 ReleaseWriteLock(&avc
->lock
);
3346 /* we have the thing in the cache */
3347 ObtainWriteLock(&tdc
->lock
, 661);
3348 if (afs_LocalHero(avc
, tdc
, &OutDirStatus
, 1)) {
3349 /* we can do it locally */
3350 code
= afs_dir_Delete(tdc
, bufp
);
3352 ZapDCE(tdc
); /* surprise error -- invalid value */
3356 ReleaseWriteLock(&tdc
->lock
);
3357 afs_PutDCache(tdc
); /* drop ref count */
3359 avc
->f
.states
&= ~CUnique
; /* For the dfs xlator */
3360 ReleaseWriteLock(&avc
->lock
);
3363 if (sysState
.allocked
)
3364 osi_FreeLargeSpace(bufp
);
3369 * VIOC_GETCELLSTATUS (35) - Get cell status info
3373 * \param[in] ain The cell you want status information on
3374 * \param[out] aout cell state (as a struct)
3376 * \retval EIO Error if the afs daemon hasn't started yet
3377 * \retval ENOENT Error if the cell doesn't exist
3379 * \post Returns the state of the cell as defined in a struct cell
3381 DECL_PIOCTL(PGetCellStatus
)
3387 AFS_STATCNT(PGetCellStatus
);
3388 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3389 return EIO
; /* Inappropriate ioctl for device */
3391 if (afs_pd_getStringPtr(ain
, &cellName
) != 0)
3394 tcell
= afs_GetCellByName(cellName
, READ_LOCK
);
3397 temp
= tcell
->states
;
3398 afs_PutCell(tcell
, READ_LOCK
);
3400 return afs_pd_putInt(aout
, temp
);
3404 * VIOC_SETCELLSTATUS (36) - Set corresponding info
3409 * The cell you want to set information about, and the values you
3414 * \retval EIO Error if the afs daemon hasn't started yet
3415 * \retval EACCES Error if the user doesn't have super-user credentials
3418 * Set the state of the cell in a defined struct cell, based on
3419 * whether or not SetUID is allowed
3421 DECL_PIOCTL(PSetCellStatus
)
3425 afs_int32 flags0
, flags1
;
3427 if (!afs_osi_suser(*acred
))
3429 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3430 return EIO
; /* Inappropriate ioctl for device */
3432 if (afs_pd_getInt(ain
, &flags0
) != 0)
3434 if (afs_pd_getInt(ain
, &flags1
) != 0)
3436 if (afs_pd_getStringPtr(ain
, &cellName
) != 0)
3439 tcell
= afs_GetCellByName(cellName
, WRITE_LOCK
);
3442 if (flags0
& CNoSUID
)
3443 tcell
->states
|= CNoSUID
;
3445 tcell
->states
&= ~CNoSUID
;
3446 afs_PutCell(tcell
, WRITE_LOCK
);
3451 FlushVolumeData(struct VenusFid
*afid
, afs_ucred_t
* acred
)
3459 afs_int32 volume
= 0;
3460 struct afs_q
*tq
, *uq
;
3462 #ifdef AFS_DARWIN80_ENV
3469 volume
= afid
->Fid
.Volume
; /* who to zap */
3474 * Clear stat'd flag from all vnodes from this volume; this will
3475 * invalidate all the vcaches associated with the volume.
3478 ObtainReadLock(&afs_xvcache
);
3479 for (i
= (afid
? VCHashV(afid
) : 0); i
< VCSIZE
; i
= (afid
? VCSIZE
: i
+1)) {
3480 for (tq
= afs_vhashTV
[i
].prev
; tq
!= &afs_vhashTV
[i
]; tq
= uq
) {
3483 if (all
|| (tvc
->f
.fid
.Fid
.Volume
== volume
&& tvc
->f
.fid
.Cell
== cell
)) {
3484 if (tvc
->f
.states
& CVInit
) {
3485 ReleaseReadLock(&afs_xvcache
);
3486 afs_osi_Sleep(&tvc
->f
.states
);
3489 #ifdef AFS_DARWIN80_ENV
3490 if (tvc
->f
.states
& CDeadVnode
) {
3491 ReleaseReadLock(&afs_xvcache
);
3492 afs_osi_Sleep(&tvc
->f
.states
);
3498 if (vnode_ref(vp
)) {
3507 ReleaseReadLock(&afs_xvcache
);
3508 ObtainWriteLock(&tvc
->lock
, 232);
3509 afs_ResetVCache(tvc
, acred
, 1);
3510 ReleaseWriteLock(&tvc
->lock
);
3511 #ifdef AFS_DARWIN80_ENV
3512 vnode_put(AFSTOV(tvc
));
3514 ObtainReadLock(&afs_xvcache
);
3516 /* our tvc ptr is still good until now */
3521 ReleaseReadLock(&afs_xvcache
);
3524 ObtainWriteLock(&afs_xdcache
, 328); /* needed to flush any stuff */
3525 for (i
= 0; i
< afs_cacheFiles
; i
++) {
3526 if (!(afs_indexFlags
[i
] & IFEverUsed
))
3527 continue; /* never had any data */
3528 tdc
= afs_GetValidDSlot(i
);
3533 if (tdc
->refCount
<= 1) { /* too high, in use by running sys call */
3534 ReleaseReadLock(&tdc
->tlock
);
3535 if (all
|| (tdc
->f
.fid
.Fid
.Volume
== volume
&& tdc
->f
.fid
.Cell
== cell
)) {
3536 if (!(afs_indexFlags
[i
] & (IFDataMod
| IFFree
| IFDiscarded
))) {
3537 /* if the file is modified, but has a ref cnt of only 1,
3538 * then someone probably has the file open and is writing
3539 * into it. Better to skip flushing such a file, it will be
3540 * brought back immediately on the next write anyway.
3542 * Skip if already freed.
3544 * If we *must* flush, then this code has to be rearranged
3545 * to call afs_storeAllSegments() first */
3546 afs_FlushDCache(tdc
);
3550 ReleaseReadLock(&tdc
->tlock
);
3552 afs_PutDCache(tdc
); /* bumped by getdslot */
3554 ReleaseWriteLock(&afs_xdcache
);
3556 ObtainReadLock(&afs_xvolume
);
3557 for (i
= all
? 0 : VHash(volume
); i
< NVOLS
; i
++) {
3558 for (tv
= afs_volumes
[i
]; tv
; tv
= tv
->next
) {
3559 if (all
|| tv
->volume
== volume
) {
3560 afs_ResetVolumeInfo(tv
);
3567 ReleaseReadLock(&afs_xvolume
);
3569 /* probably, a user is doing this, probably, because things are screwed up.
3570 * maybe it's the dnlc's fault? */
3576 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
3580 * \param[in] ain not in use (args in avc)
3581 * \param[out] aout not in use
3583 * \retval EINVAL Error if some of the standard args aren't set
3584 * \retval EIO Error if the afs daemon hasn't started yet
3587 * Flush all cached contents of a volume. Exactly what stays and what
3588 * goes depends on the platform.
3591 * Does not flush a file that a user has open and is using, because
3592 * it will be re-created on next write. Also purges the dnlc,
3593 * because things are screwed up.
3595 DECL_PIOCTL(PFlushVolumeData
)
3597 AFS_STATCNT(PFlushVolumeData
);
3600 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3601 return EIO
; /* Inappropriate ioctl for device */
3603 return FlushVolumeData(&avc
->f
.fid
, *acred
);
3607 * VIOC_FLUSHALL (14) - Flush whole volume's data for all volumes
3611 * \param[in] ain not in use
3612 * \param[out] aout not in use
3614 * \retval EINVAL Error if some of the standard args aren't set
3615 * \retval EIO Error if the afs daemon hasn't started yet
3618 * Flush all cached contents. Exactly what stays and what
3619 * goes depends on the platform.
3622 * Does not flush a file that a user has open and is using, because
3623 * it will be re-created on next write. Also purges the dnlc,
3624 * because things are screwed up.
3626 DECL_PIOCTL(PFlushAllVolumeData
)
3628 AFS_STATCNT(PFlushAllVolumeData
);
3630 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
3631 return EIO
; /* Inappropriate ioctl for device */
3633 return FlushVolumeData(NULL
, *acred
);
3637 * VIOCGETVCXSTATUS (41) - gets vnode x status
3642 * not in use (avc used)
3644 * vcxstat: the file id, the data version, any lock, the parent vnode,
3645 * the parent unique id, the trunc position, the callback, cbExpires,
3646 * what access is being made, what files are open,
3647 * any users executing/writing, the flock count, the states,
3651 * Error if some of the initial default arguments aren't set
3653 * Error if access to check the mode bits is denied
3656 * gets stats for the vnode, a struct listed in vcxstat
3658 DECL_PIOCTL(PGetVnodeXStatus
)
3661 struct vcxstat stat
;
3664 /* AFS_STATCNT(PGetVnodeXStatus); */
3667 code
= afs_VerifyVCache(avc
, areq
);
3670 if (vType(avc
) == VDIR
)
3671 mode
= PRSFS_LOOKUP
;
3674 if (!afs_AccessOK(avc
, mode
, areq
, CHECK_MODE_BITS
))
3677 memset(&stat
, 0, sizeof(struct vcxstat
));
3678 stat
.fid
= avc
->f
.fid
;
3679 hset32(stat
.DataVersion
, hgetlo(avc
->f
.m
.DataVersion
));
3680 stat
.lock
= avc
->lock
;
3681 stat
.parentVnode
= avc
->f
.parent
.vnode
;
3682 stat
.parentUnique
= avc
->f
.parent
.unique
;
3683 hset(stat
.flushDV
, avc
->flushDV
);
3684 hset(stat
.mapDV
, avc
->mapDV
);
3685 stat
.truncPos
= avc
->f
.truncPos
;
3686 { /* just grab the first two - won't break anything... */
3687 struct axscache
*ac
;
3689 for (i
= 0, ac
= avc
->Access
; ac
&& i
< CPSIZE
; i
++, ac
= ac
->next
) {
3690 stat
.randomUid
[i
] = ac
->uid
;
3691 stat
.randomAccess
[i
] = ac
->axess
;
3694 stat
.callback
= afs_data_pointer_to_int32(avc
->callback
);
3695 stat
.cbExpires
= avc
->cbExpires
;
3696 stat
.anyAccess
= avc
->f
.anyAccess
;
3697 stat
.opens
= avc
->opens
;
3698 stat
.execsOrWriters
= avc
->execsOrWriters
;
3699 stat
.flockCount
= avc
->flockCount
;
3700 stat
.mvstat
= avc
->mvstat
;
3701 stat
.states
= avc
->f
.states
;
3702 return afs_pd_putBytes(aout
, &stat
, sizeof(struct vcxstat
));
3706 DECL_PIOCTL(PGetVnodeXStatus2
)
3709 struct vcxstat2 stat
;
3714 code
= afs_VerifyVCache(avc
, areq
);
3717 if (vType(avc
) == VDIR
)
3718 mode
= PRSFS_LOOKUP
;
3721 if (!afs_AccessOK(avc
, mode
, areq
, CHECK_MODE_BITS
))
3724 memset(&stat
, 0, sizeof(struct vcxstat2
));
3726 stat
.cbExpires
= avc
->cbExpires
;
3727 stat
.anyAccess
= avc
->f
.anyAccess
;
3728 stat
.mvstat
= avc
->mvstat
;
3729 stat
.callerAccess
= afs_GetAccessBits(avc
, ~0, areq
);
3731 return afs_pd_putBytes(aout
, &stat
, sizeof(struct vcxstat2
));
3736 * VIOC_AFS_SYSNAME (38) - Change @sys value
3740 * \param[in] ain new value for @sys
3741 * \param[out] aout count, entry, list (debug values?)
3744 * Error if afsd isn't running, the new sysname is too large,
3745 * the new sysname causes issues (starts with a . or ..),
3746 * there is no PAG set in the credentials, or the user of a PAG
3749 * Error if the user doesn't have super-user credentials
3752 * Set the value of @sys if these things work: if the input isn't
3753 * too long or if input doesn't start with . or ..
3756 * We require root for local sysname changes, but not for remote
3757 * (since we don't really believe remote uids anyway)
3758 * outname[] shouldn't really be needed- this is left as an
3759 * exercise for the reader.
3761 DECL_PIOCTL(PSetSysName
)
3763 char *inname
= NULL
;
3764 char outname
[MAXSYSNAME
];
3765 afs_int32 setsysname
;
3767 struct afs_exporter
*exporter
;
3768 struct unixuser
*au
;
3769 afs_int32 pag
, error
;
3770 int t
, count
, num
= 0, allpags
= 0;
3772 struct afs_pdata validate
;
3774 AFS_STATCNT(PSetSysName
);
3775 if (!afs_globalVFS
) {
3776 /* Afsd is NOT running; disable it */
3777 #if defined(KERNEL_HAVE_UERROR)
3778 return (setuerror(EINVAL
), EINVAL
);
3783 if (afs_pd_getInt(ain
, &setsysname
) != 0)
3785 if (setsysname
& 0x8000) {
3787 setsysname
&= ~0x8000;
3792 if (setsysname
< 0 || setsysname
> MAXNUMSYSNAMES
)
3795 for (count
= 0; count
< setsysname
; count
++) {
3796 if (afs_pd_getStringPtr(&validate
, &inname
) != 0)
3799 if (t
>= MAXSYSNAME
|| t
<= 0)
3801 /* check for names that can shoot us in the foot */
3802 if (inname
[0] == '.' && (inname
[1] == 0
3803 || (inname
[1] == '.' && inname
[2] == 0)))
3806 /* args ok, so go back to the beginning of that section */
3808 if (afs_pd_getStringPtr(ain
, &inname
) != 0)
3812 if (afs_rmtsys_enable
&& (afs_cr_gid(*acred
) == RMTUSER_REQ
||
3813 afs_cr_gid(*acred
) == RMTUSER_REQ_PRIV
)) { /* Handles all exporters */
3814 if (allpags
&& afs_cr_gid(*acred
) != RMTUSER_REQ_PRIV
) {
3817 pag
= PagInCred(*acred
);
3819 return EINVAL
; /* Better than panicing */
3821 if (!(au
= afs_FindUser(pag
, -1, READ_LOCK
))) {
3822 return EINVAL
; /* Better than panicing */
3824 if (!(exporter
= au
->exporter
)) {
3825 afs_PutUser(au
, READ_LOCK
);
3826 return EINVAL
; /* Better than panicing */
3828 error
= EXP_SYSNAME(exporter
, inname
, &sysnamelist
,
3831 if (error
== ENODEV
)
3832 foundname
= 0; /* sysname not set yet! */
3834 afs_PutUser(au
, READ_LOCK
);
3839 strcpy(outname
, sysnamelist
[0]);
3841 afs_PutUser(au
, READ_LOCK
);
3845 /* Not xlating, so local case */
3847 osi_Panic("PSetSysName: !afs_sysname\n");
3848 if (!setsysname
) { /* user just wants the info */
3849 strcpy(outname
, afs_sysname
);
3850 foundname
= afs_sysnamecount
;
3851 sysnamelist
= afs_sysnamelist
;
3852 } else { /* Local guy; only root can change sysname */
3853 if (!afs_osi_suser(*acred
))
3856 /* allpags makes no sense for local use */
3860 /* clear @sys entries from the dnlc, once afs_lookup can
3861 * do lookups of @sys entries and thinks it can trust them */
3862 /* privs ok, store the entry, ... */
3864 if (strlen(inname
) >= MAXSYSNAME
-1)
3866 strcpy(afs_sysname
, inname
);
3868 if (setsysname
> 1) { /* ... or list */
3869 for (count
= 1; count
< setsysname
; ++count
) {
3870 if (!afs_sysnamelist
[count
])
3872 ("PSetSysName: no afs_sysnamelist entry to write\n");
3873 if (afs_pd_getString(ain
, afs_sysnamelist
[count
],
3878 afs_sysnamecount
= setsysname
;
3883 if (afs_pd_putInt(aout
, foundname
) != 0)
3886 if (afs_pd_putString(aout
, outname
) != 0)
3888 for (count
= 1; count
< foundname
; ++count
) { /* ... or list. */
3889 if (!sysnamelist
[count
])
3891 ("PSetSysName: no afs_sysnamelist entry to read\n");
3892 t
= strlen(sysnamelist
[count
]);
3893 if (t
>= MAXSYSNAME
)
3894 osi_Panic("PSetSysName: sysname entry garbled\n");
3895 if (afs_pd_putString(aout
, sysnamelist
[count
]) != 0)
3903 /* sequential search through the list of touched cells is not a good
3904 * long-term solution here. For small n, though, it should be just
3905 * fine. Should consider special-casing the local cell for large n.
3906 * Likewise for PSetSPrefs.
3908 * s - number of ids in array l[] -- NOT index of last id
3909 * l - array of cell ids which have volumes that need to be sorted
3910 * vlonly - sort vl servers or file servers?
3913 ReSortCells_cb(struct cell
*cell
, void *arg
)
3915 afs_int32
*p
= (afs_int32
*) arg
;
3916 afs_int32
*l
= p
+ 1;
3919 for (i
= 0; i
< s
; i
++) {
3920 if (l
[i
] == cell
->cellNum
) {
3921 ObtainWriteLock(&cell
->lock
, 690);
3922 afs_SortServers(cell
->cellHosts
, AFS_MAXCELLHOSTS
);
3923 ReleaseWriteLock(&cell
->lock
);
3931 ReSortCells(int s
, afs_int32
* l
, int vlonly
)
3939 p
= afs_osi_Alloc(sizeof(afs_int32
) * (s
+ 1));
3940 osi_Assert(p
!= NULL
);
3942 memcpy(p
+ 1, l
, s
* sizeof(afs_int32
));
3943 afs_TraverseCells(&ReSortCells_cb
, p
);
3944 afs_osi_Free(p
, sizeof(afs_int32
) * (s
+ 1));
3948 ObtainReadLock(&afs_xvolume
);
3949 for (i
= 0; i
< NVOLS
; i
++) {
3950 for (j
= afs_volumes
[i
]; j
; j
= j
->next
) {
3951 for (k
= 0; k
< s
; k
++)
3952 if (j
->cell
== l
[k
]) {
3953 ObtainWriteLock(&j
->lock
, 233);
3954 afs_SortServers(j
->serverHost
, AFS_MAXHOSTS
);
3955 ReleaseWriteLock(&j
->lock
);
3960 ReleaseReadLock(&afs_xvolume
);
3964 static int debugsetsp
= 0;
3966 afs_setsprefs(struct spref
*sp
, unsigned int num
, unsigned int vlonly
)
3969 int i
, j
, k
, matches
, touchedSize
;
3970 struct server
*srvr
= NULL
;
3971 afs_int32 touched
[34];
3975 for (k
= 0; k
< num
; sp
++, k
++) {
3977 afs_warn("sp host=%x, rank=%d\n", sp
->host
.s_addr
, sp
->rank
);
3980 ObtainReadLock(&afs_xserver
);
3982 i
= SHash(sp
->host
.s_addr
);
3983 for (sa
= afs_srvAddrs
[i
]; sa
; sa
= sa
->next_bkt
) {
3984 if (sa
->sa_ip
== sp
->host
.s_addr
) {
3986 isfs
= (srvr
->cell
&& (sa
->sa_portal
== srvr
->cell
->fsport
))
3987 || (sa
->sa_portal
== AFS_FSPORT
);
3988 if ((!vlonly
&& isfs
) || (vlonly
&& !isfs
)) {
3995 if (sa
&& matches
) { /* found one! */
3997 afs_warn("sa ip=%x, ip_rank=%d\n", sa
->sa_ip
, sa
->sa_iprank
);
3999 sa
->sa_iprank
= sp
->rank
+ afs_randomMod15();
4000 afs_SortOneServer(sa
->server
);
4003 /* if we don't know yet what cell it's in, this is moot */
4004 for (j
= touchedSize
- 1;
4005 j
>= 0 && touched
[j
] != srvr
->cell
->cellNum
; j
--)
4006 /* is it in our list of touched cells ? */ ;
4007 if (j
< 0) { /* no, it's not */
4008 touched
[touchedSize
++] = srvr
->cell
->cellNum
;
4009 if (touchedSize
>= 32) { /* watch for ovrflow */
4010 ReleaseReadLock(&afs_xserver
);
4011 ReSortCells(touchedSize
, touched
, vlonly
);
4013 ObtainReadLock(&afs_xserver
);
4019 ReleaseReadLock(&afs_xserver
);
4020 /* if we didn't find one, start to create one. */
4021 /* Note that it doesn't have a cell yet... */
4023 afs_uint32 temp
= sp
->host
.s_addr
;
4025 afs_GetServer(&temp
, 1, 0, (vlonly
? AFS_VLPORT
: AFS_FSPORT
),
4026 WRITE_LOCK
, (afsUUID
*) 0, 0, NULL
);
4027 srvr
->addr
->sa_iprank
= sp
->rank
+ afs_randomMod15();
4028 afs_PutServer(srvr
, WRITE_LOCK
);
4030 } /* for all cited preferences */
4032 ReSortCells(touchedSize
, touched
, vlonly
);
4037 * VIOC_SETPREFS (46) - Set server ranks
4039 * \param[in] ain the sprefs value you want the sprefs to be set to
4040 * \param[out] aout not in use
4043 * Error if the afs daemon hasn't started yet
4045 * Error if the user doesn't have super-user credentials
4047 * Error if the struct setsprefs is too large or if it multiplied
4048 * by the number of servers is too large
4050 * \post set the sprefs using the afs_setsprefs() function
4052 DECL_PIOCTL(PSetSPrefs
)
4054 struct setspref
*ssp
;
4058 AFS_STATCNT(PSetSPrefs
);
4060 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4061 return EIO
; /* Inappropriate ioctl for device */
4063 if (!afs_osi_suser(*acred
))
4066 /* The I/O handling here is ghastly, as it relies on overrunning the ends
4067 * of arrays. But, i'm not quite brave enough to change it yet. */
4069 ainSize
= ain
->remaining
;
4071 if (ainSize
< sizeof(struct setspref
))
4074 ssp
= (struct setspref
*)ainPtr
;
4075 if (ainSize
< (sizeof(struct setspref
)
4076 + sizeof(struct spref
) * (ssp
->num_servers
-1)))
4079 afs_setsprefs(&(ssp
->servers
[0]), ssp
->num_servers
,
4080 (ssp
->flags
& DBservers
));
4085 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
4087 * \param[in] ain the server preferences to be set
4088 * \param[out] aout not in use
4090 * \retval EIO Error if the afs daemon hasn't started yet
4091 * \retval EACCES Error if the user doesn't have super-user credentials
4093 * \post set the server preferences, calling a function
4095 * \notes this may only be performed by the local root user.
4097 DECL_PIOCTL(PSetSPrefs33
)
4099 AFS_STATCNT(PSetSPrefs
);
4100 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4101 return EIO
; /* Inappropriate ioctl for device */
4104 if (!afs_osi_suser(*acred
))
4107 afs_setsprefs((struct spref
*)afs_pd_where(ain
),
4108 afs_pd_remaining(ain
) / sizeof(struct spref
),
4114 * VIOC_GETSPREFS (43) - Get server ranks
4118 * \param[in] ain the server preferences to get
4119 * \param[out] aout the server preferences information
4121 * \retval EIO Error if the afs daemon hasn't started yet
4122 * \retval ENOENT Error if the sprefrequest is too large
4124 * \post Get the sprefs
4127 * in the hash table of server structs, all servers with the same
4128 * IP address; will be on the same overflow chain; This could be
4129 * sped slightly in some circumstances by having it cache the
4130 * immediately previous slot in the hash table and some
4131 * supporting information; Only reports file servers now.
4133 DECL_PIOCTL(PGetSPrefs
)
4135 struct sprefrequest spin
; /* input */
4136 struct sprefinfo
*spout
; /* output */
4137 struct spref
*srvout
; /* one output component */
4138 int i
, j
; /* counters for hash table traversal */
4139 struct server
*srvr
; /* one of CM's server structs */
4141 int vlonly
; /* just return vlservers ? */
4144 AFS_STATCNT(PGetSPrefs
);
4145 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4146 return EIO
; /* Inappropriate ioctl for device */
4148 /* Work out from the size whether we've got a new, or old, style pioctl */
4149 if (afs_pd_remaining(ain
) < sizeof(struct sprefrequest
)) {
4150 if (afs_pd_getBytes(ain
, &spin
, sizeof(struct sprefrequest_33
)) != 0)
4155 if (afs_pd_getBytes(ain
, &spin
, sizeof(struct sprefrequest
)) != 0)
4157 vlonly
= (spin
.flags
& DBservers
);
4160 /* This code relies on overflowing arrays. It's ghastly, but I'm not
4161 * quite brave enough to tackle it yet ...
4164 /* struct sprefinfo includes 1 server struct... that size gets added
4165 * in during the loop that follows.
4167 spout
= afs_pd_inline(aout
,
4168 sizeof(struct sprefinfo
) - sizeof(struct spref
));
4169 spout
->next_offset
= spin
.offset
;
4170 spout
->num_servers
= 0;
4171 srvout
= spout
->servers
;
4173 ObtainReadLock(&afs_xserver
);
4174 for (i
= 0, j
= 0; j
< NSERVERS
; j
++) { /* sift through hash table */
4175 for (sa
= afs_srvAddrs
[j
]; sa
; sa
= sa
->next_bkt
, i
++) {
4176 if (spin
.offset
> (unsigned short)i
) {
4177 continue; /* catch up to where we left off */
4179 spout
->next_offset
++;
4182 isfs
= (srvr
->cell
&& (sa
->sa_portal
== srvr
->cell
->fsport
))
4183 || (sa
->sa_portal
== AFS_FSPORT
);
4185 if ((vlonly
&& isfs
) || (!vlonly
&& !isfs
)) {
4186 /* only report ranks for vl servers */
4190 /* Check we've actually got the space we're about to use */
4191 if (afs_pd_inline(aout
, sizeof(struct spref
)) == NULL
) {
4192 ReleaseReadLock(&afs_xserver
); /* no more room! */
4196 srvout
->host
.s_addr
= sa
->sa_ip
;
4197 srvout
->rank
= sa
->sa_iprank
;
4198 spout
->num_servers
++;
4202 ReleaseReadLock(&afs_xserver
);
4204 spout
->next_offset
= 0; /* start over from the beginning next time */
4209 /* Enable/Disable the specified exporter. Must be root to disable an exporter */
4210 int afs_NFSRootOnly
= 1;
4212 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
4217 * an integer containing the desired exportee flags
4219 * an integer containing the current exporter flags
4221 * \retval ENODEV Error if the exporter doesn't exist
4222 * \retval EACCES Error if the user doesn't have super-user credentials
4225 * Changes the state of various values to reflect the change
4226 * of the export values between nfs and afs.
4228 * \notes Legacy code obtained from IBM.
4230 DECL_PIOCTL(PExportAfs
)
4232 afs_int32 export
, newint
= 0;
4233 afs_int32 type
, changestate
, handleValue
, convmode
, pwsync
, smounts
;
4234 afs_int32 rempags
= 0, pagcb
= 0;
4235 struct afs_exporter
*exporter
;
4237 AFS_STATCNT(PExportAfs
);
4238 if (afs_pd_getInt(ain
, &handleValue
) != 0)
4240 type
= handleValue
>> 24;
4245 exporter
= exporter_find(type
);
4247 export
= handleValue
& 3;
4248 changestate
= handleValue
& 0xfff;
4249 smounts
= (handleValue
>> 2) & 3;
4250 pwsync
= (handleValue
>> 4) & 3;
4251 convmode
= (handleValue
>> 6) & 3;
4252 rempags
= (handleValue
>> 8) & 3;
4253 pagcb
= (handleValue
>> 10) & 3;
4255 changestate
= (handleValue
>> 16) & 0x1;
4256 convmode
= (handleValue
>> 16) & 0x2;
4257 pwsync
= (handleValue
>> 16) & 0x4;
4258 smounts
= (handleValue
>> 16) & 0x8;
4259 export
= handleValue
& 0xff;
4262 /* Failed finding desired exporter; */
4266 handleValue
= exporter
->exp_states
;
4267 if (afs_pd_putInt(aout
, handleValue
) != 0)
4270 if (!afs_osi_suser(*acred
))
4271 return EACCES
; /* Only superuser can do this */
4275 exporter
->exp_states
|= EXP_EXPORTED
;
4277 exporter
->exp_states
&= ~EXP_EXPORTED
;
4281 exporter
->exp_states
|= EXP_UNIXMODE
;
4283 exporter
->exp_states
&= ~EXP_UNIXMODE
;
4287 exporter
->exp_states
|= EXP_PWSYNC
;
4289 exporter
->exp_states
&= ~EXP_PWSYNC
;
4293 afs_NFSRootOnly
= 0;
4294 exporter
->exp_states
|= EXP_SUBMOUNTS
;
4296 afs_NFSRootOnly
= 1;
4297 exporter
->exp_states
&= ~EXP_SUBMOUNTS
;
4302 exporter
->exp_states
|= EXP_CLIPAGS
;
4304 exporter
->exp_states
&= ~EXP_CLIPAGS
;
4308 exporter
->exp_states
|= EXP_CALLBACK
;
4310 exporter
->exp_states
&= ~EXP_CALLBACK
;
4312 handleValue
= exporter
->exp_states
;
4313 if (afs_pd_putInt(aout
, handleValue
) != 0)
4317 exporter
->exp_states
|= EXP_EXPORTED
;
4319 exporter
->exp_states
&= ~EXP_EXPORTED
;
4321 exporter
->exp_states
|= EXP_UNIXMODE
;
4323 exporter
->exp_states
&= ~EXP_UNIXMODE
;
4325 exporter
->exp_states
|= EXP_PWSYNC
;
4327 exporter
->exp_states
&= ~EXP_PWSYNC
;
4329 afs_NFSRootOnly
= 0;
4330 exporter
->exp_states
|= EXP_SUBMOUNTS
;
4332 afs_NFSRootOnly
= 1;
4333 exporter
->exp_states
&= ~EXP_SUBMOUNTS
;
4342 * VIOC_GAG (44) - Silence Cache Manager
4346 * \param[in] ain the flags to either gag or de-gag the cache manager
4347 * \param[out] aout not in use
4349 * \retval EACCES Error if the user doesn't have super-user credentials
4351 * \post set the gag flags, then show these flags
4355 struct gaginfo
*gagflags
;
4357 if (!afs_osi_suser(*acred
))
4360 gagflags
= afs_pd_inline(ain
, sizeof(*gagflags
));
4361 if (gagflags
== NULL
)
4363 afs_showflags
= gagflags
->showflags
;
4369 * VIOC_TWIDDLE (45) - Adjust RX knobs
4373 * \param[in] ain the previous settings of the 'knobs'
4374 * \param[out] aout not in use
4376 * \retval EACCES Error if the user doesn't have super-user credentials
4378 * \post build out the struct rxp, from a struct rx
4380 DECL_PIOCTL(PTwiddleRx
)
4382 struct rxparams
*rxp
;
4384 if (!afs_osi_suser(*acred
))
4387 rxp
= afs_pd_inline(ain
, sizeof(*rxp
));
4391 if (rxp
->rx_initReceiveWindow
)
4392 rx_initReceiveWindow
= rxp
->rx_initReceiveWindow
;
4393 if (rxp
->rx_maxReceiveWindow
)
4394 rx_maxReceiveWindow
= rxp
->rx_maxReceiveWindow
;
4395 if (rxp
->rx_initSendWindow
)
4396 rx_initSendWindow
= rxp
->rx_initSendWindow
;
4397 if (rxp
->rx_maxSendWindow
)
4398 rx_maxSendWindow
= rxp
->rx_maxSendWindow
;
4399 if (rxp
->rxi_nSendFrags
)
4400 rxi_nSendFrags
= rxp
->rxi_nSendFrags
;
4401 if (rxp
->rxi_nRecvFrags
)
4402 rxi_nRecvFrags
= rxp
->rxi_nRecvFrags
;
4403 if (rxp
->rxi_OrphanFragSize
)
4404 rxi_OrphanFragSize
= rxp
->rxi_OrphanFragSize
;
4405 if (rxp
->rx_maxReceiveSize
) {
4406 rx_maxReceiveSize
= rxp
->rx_maxReceiveSize
;
4407 rx_maxReceiveSizeUser
= rxp
->rx_maxReceiveSize
;
4409 if (rxp
->rx_MyMaxSendSize
)
4410 rx_MyMaxSendSize
= rxp
->rx_MyMaxSendSize
;
4416 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
4420 * \param[in] ain not in use
4421 * \param[out] aout initial cache manager params
4424 * Error if the initial parameters are bigger than some PIGGYSIZE
4426 * \post return the initial cache manager parameters
4428 DECL_PIOCTL(PGetInitParams
)
4430 if (sizeof(struct cm_initparams
) > PIGGYSIZE
)
4433 return afs_pd_putBytes(aout
, &cm_initParams
,
4434 sizeof(struct cm_initparams
));
4437 #ifdef AFS_SGI65_ENV
4438 /* They took crget() from us, so fake it. */
4443 cr
= crdup(get_current_cred());
4444 memset(cr
, 0, sizeof(cred_t
));
4445 #if CELL || CELL_PREPARE
4453 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
4457 * \param[in] ain not in use
4458 * \param[out] aout value of cryptall
4460 * \post Turns on, or disables, rxkad encryption by setting the cryptall global
4462 DECL_PIOCTL(PGetRxkcrypt
)
4464 return afs_pd_putInt(aout
, cryptall
);
4468 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
4472 * \param[in] ain the argument whether or not things should be encrypted
4473 * \param[out] aout not in use
4476 * Error if the user doesn't have super-user credentials
4478 * Error if the input is too big, or if the input is outside the
4479 * bounds of what it can be set to
4481 * \post set whether or not things should be encrypted
4484 * may need to be modified at a later date to take into account
4485 * other values for cryptall (beyond true or false)
4487 DECL_PIOCTL(PSetRxkcrypt
)
4491 if (!afs_osi_suser(*acred
))
4493 if (afs_pd_getInt(ain
, &tmpval
) != 0)
4495 /* if new mappings added later this will need to be changed */
4496 if (tmpval
!= 0 && tmpval
!= 1)
4502 #ifdef AFS_NEED_CLIENTCONTEXT
4504 * Create new credentials to correspond to a remote user with given
4505 * <hostaddr, uid, g0, g1>. This allows a server running as root to
4506 * provide pioctl (and other) services to foreign clients (i.e. nfs
4507 * clients) by using this call to `become' the client.
4510 #define PIOCTL_HEADER 6
4512 HandleClientContext(struct afs_ioctl
*ablob
, int *com
,
4513 afs_ucred_t
**acred
, afs_ucred_t
*credp
)
4516 afs_uint32 hostaddr
;
4517 afs_int32 uid
, g0
, g1
, i
, code
, pag
, exporter_type
, isroot
= 0;
4518 struct afs_exporter
*exporter
, *outexporter
;
4519 afs_ucred_t
*newcred
;
4520 struct unixuser
*au
;
4521 afs_uint32 comp
= *com
& 0xff00;
4523 #if defined(AFS_SUN510_ENV)
4527 #if defined(AFS_SGIMP_ENV)
4528 osi_Assert(ISAFS_GLOCK());
4530 AFS_STATCNT(HandleClientContext
);
4531 if (ablob
->in_size
< PIOCTL_HEADER
* sizeof(afs_int32
)) {
4532 /* Must at least include the PIOCTL_HEADER header words
4533 * required by the protocol */
4534 return EINVAL
; /* Too small to be good */
4536 ain
= inData
= osi_AllocLargeSpace(AFS_LRALLOCSIZ
);
4537 AFS_COPYIN(ablob
->in
, ain
, PIOCTL_HEADER
* sizeof(afs_int32
), code
);
4539 osi_FreeLargeSpace(inData
);
4543 /* Extract information for remote user */
4544 hostaddr
= *((afs_uint32
*) ain
);
4545 ain
+= sizeof(hostaddr
);
4546 uid
= *((afs_uint32
*) ain
);
4548 g0
= *((afs_uint32
*) ain
);
4550 g1
= *((afs_uint32
*) ain
);
4552 *com
= *((afs_uint32
*) ain
);
4553 ain
+= sizeof(afs_int32
);
4554 exporter_type
= *((afs_uint32
*) ain
);/* In case we support more than NFS */
4557 * Of course, one must be root for most of these functions, but
4558 * we'll allow (for knfs) you to set things if the pag is 0 and
4559 * you're setting tokens or unlogging.
4562 if (!afs_osi_suser(credp
)) {
4563 #if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
4564 /* Since SGI's suser() returns explicit failure after the call.. */
4567 /* check for acceptable opcodes for normal folks, which are, so far,
4568 * get/set tokens, sysname, and unlog.
4570 if (i
!= 9 && i
!= 3 && i
!= 38 && i
!= 8) {
4571 osi_FreeLargeSpace(inData
);
4576 ablob
->in_size
-= PIOCTL_HEADER
* sizeof(afs_int32
);
4577 ablob
->in
+= PIOCTL_HEADER
* sizeof(afs_int32
);
4578 osi_FreeLargeSpace(inData
);
4581 * We map uid 0 to nobody to match the mapping that the nfs
4582 * server does and to ensure that the suser() calls in the afs
4583 * code fails for remote client roots.
4585 uid
= afs_nobody
; /* NFS_NOBODY == -2 */
4589 #ifdef AFS_AIX41_ENV
4592 afs_set_cr_gid(newcred
, isroot
? RMTUSER_REQ_PRIV
: RMTUSER_REQ
);
4593 #ifdef AFS_AIX51_ENV
4594 newcred
->cr_groupset
.gs_union
.un_groups
[0] = g0
;
4595 newcred
->cr_groupset
.gs_union
.un_groups
[1] = g1
;
4596 #elif defined(AFS_LINUX26_ENV)
4597 # ifdef AFS_PAG_ONEGROUP_ENV
4598 afs_set_cr_group_info(newcred
, groups_alloc(1)); /* nothing sets this */
4599 l
= (((g0
-0x3f00) & 0x3fff) << 14) | ((g1
-0x3f00) & 0x3fff);
4600 h
= ((g0
-0x3f00) >> 14);
4601 h
= ((g1
-0x3f00) >> 14) + h
+ h
+ h
;
4602 GROUP_AT(afs_cr_group_info(newcred
), 0) = ((h
<< 28) | l
);
4604 afs_set_cr_group_info(newcred
, groups_alloc(2));
4605 GROUP_AT(afs_cr_group_info(newcred
), 0) = g0
;
4606 GROUP_AT(afs_cr_group_info(newcred
), 1) = g1
;
4608 #elif defined(AFS_SUN510_ENV)
4609 # ifdef AFS_PAG_ONEGROUP_ENV
4610 gids
[0] = afs_get_pag_from_groups(g0
, g1
);
4611 crsetgroups(newcred
, 1, gids
);
4615 crsetgroups(newcred
, 2, gids
);
4616 # endif /* !AFS_PAG_ONEGROUP_ENV */
4618 newcred
->cr_groups
[0] = g0
;
4619 newcred
->cr_groups
[1] = g1
;
4622 newcred
->cr_ngrps
= 2;
4623 #elif !defined(AFS_LINUX26_ENV) && !defined(AFS_SUN510_ENV)
4624 # if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_FBSD80_ENV)
4625 newcred
->cr_ngroups
= 2;
4627 for (i
= 2; i
< NGROUPS
; i
++)
4628 newcred
->cr_groups
[i
] = NOGROUP
;
4631 if (!(exporter
= exporter_find(exporter_type
))) {
4632 /* Exporter wasn't initialized or an invalid exporter type */
4636 if (exporter
->exp_states
& EXP_PWSYNC
) {
4637 if (uid
!= afs_cr_uid(credp
)) {
4639 return ENOEXEC
; /* XXX Find a better errno XXX */
4642 afs_set_cr_uid(newcred
, uid
); /* Only temporary */
4643 code
= EXP_REQHANDLER(exporter
, &newcred
, hostaddr
, &pag
, &outexporter
);
4644 /* The client's pag is the only unique identifier for it */
4645 afs_set_cr_uid(newcred
, pag
);
4647 if (!code
&& *com
== PSETPAG
) {
4648 /* Special case for 'setpag' */
4649 afs_uint32 pagvalue
= genpag();
4651 au
= afs_GetUser(pagvalue
, -1, WRITE_LOCK
); /* a new unixuser struct */
4653 * Note that we leave the 'outexporter' struct held so it won't
4656 au
->exporter
= outexporter
;
4657 if (ablob
->out_size
>= 4) {
4658 AFS_COPYOUT((char *)&pagvalue
, ablob
->out
, sizeof(afs_int32
),
4661 afs_PutUser(au
, WRITE_LOCK
);
4664 return PSETPAG
; /* Special return for setpag */
4666 EXP_RELE(outexporter
);
4669 *com
= (*com
) | comp
;
4672 #endif /* AFS_NEED_CLIENTCONTEXT */
4676 * VIOC_GETCPREFS (50) - Get client interface
4680 * \param[in] ain sprefrequest input
4681 * \param[out] aout spref information
4683 * \retval EIO Error if the afs daemon hasn't started yet
4684 * \retval EINVAL Error if some of the standard args aren't set
4687 * get all interface addresses and other information of the client
4690 DECL_PIOCTL(PGetCPrefs
)
4692 struct sprefrequest
*spin
; /* input */
4693 struct sprefinfo
*spout
; /* output */
4694 struct spref
*srvout
; /* one output component */
4698 AFS_STATCNT(PGetCPrefs
);
4699 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4700 return EIO
; /* Inappropriate ioctl for device */
4702 spin
= afs_pd_inline(ain
, sizeof(*spin
));
4706 /* Output spout relies on writing past the end of arrays. It's horrible,
4707 * but I'm not quite brave enough to tackle it yet */
4708 spout
= (struct sprefinfo
*)aout
->ptr
;
4710 maxNumber
= spin
->num_servers
; /* max addrs this time */
4711 srvout
= spout
->servers
;
4713 ObtainReadLock(&afs_xinterface
);
4715 /* copy out the client interface information from the
4716 * kernel data structure "interface" to the output buffer
4718 for (i
= spin
->offset
, j
= 0; (i
< afs_cb_interface
.numberOfInterfaces
)
4719 && (j
< maxNumber
); i
++, j
++, srvout
++)
4720 srvout
->host
.s_addr
= afs_cb_interface
.addr_in
[i
];
4722 spout
->num_servers
= j
;
4723 aout
->ptr
+= sizeof(struct sprefinfo
) + (j
- 1) * sizeof(struct spref
);
4725 if (i
>= afs_cb_interface
.numberOfInterfaces
)
4726 spout
->next_offset
= 0; /* start from beginning again */
4728 spout
->next_offset
= spin
->offset
+ j
;
4730 ReleaseReadLock(&afs_xinterface
);
4735 * VIOC_SETCPREFS (51) - Set client interface
4739 * \param[in] ain the interfaces you want set
4740 * \param[out] aout not in use
4742 * \retval EIO Error if the afs daemon hasn't started yet
4743 * \retval EINVAL Error if the input is too large for the struct
4744 * \retval ENOMEM Error if there are too many servers
4746 * \post set the callbak interfaces addresses to those of the hosts
4748 DECL_PIOCTL(PSetCPrefs
)
4752 struct setspref
*sin
;
4755 AFS_STATCNT(PSetCPrefs
);
4756 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
4757 return EIO
; /* Inappropriate ioctl for device */
4759 /* Yuck. Input to this function relies on reading past the end of
4760 * structures. Bodge it for now.
4763 ainSize
= ain
->remaining
;
4765 sin
= (struct setspref
*)ainPtr
;
4767 if (ainSize
< sizeof(struct setspref
))
4769 #if 0 /* num_servers is unsigned */
4770 if (sin
->num_servers
< 0)
4773 if (sin
->num_servers
> AFS_MAX_INTERFACE_ADDR
)
4776 ObtainWriteLock(&afs_xinterface
, 412);
4777 afs_cb_interface
.numberOfInterfaces
= sin
->num_servers
;
4778 for (i
= 0; (unsigned short)i
< sin
->num_servers
; i
++)
4779 afs_cb_interface
.addr_in
[i
] = sin
->servers
[i
].host
.s_addr
;
4781 ReleaseWriteLock(&afs_xinterface
);
4786 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
4791 * the last part of a path to a mount point, which tells us what to flush
4796 * Error if some of the initial arguments aren't set
4798 * Error if the initial argument for the mount point isn't a directory
4800 * Error if the dcache entry isn't set
4803 * remove all of the mount data from the dcache regarding a
4804 * certain mount point
4806 DECL_PIOCTL(PFlushMount
)
4811 struct VenusFid tfid
;
4814 struct sysname_info sysState
;
4815 afs_size_t offset
, len
;
4817 AFS_STATCNT(PFlushMount
);
4821 if (afs_pd_getStringPtr(ain
, &mount
) != 0)
4824 code
= afs_VerifyVCache(avc
, areq
);
4827 if (vType(avc
) != VDIR
) {
4830 tdc
= afs_GetDCache(avc
, (afs_size_t
) 0, areq
, &offset
, &len
, 1);
4833 Check_AtSys(avc
, mount
, &sysState
, areq
);
4834 ObtainReadLock(&tdc
->lock
);
4836 code
= afs_dir_Lookup(tdc
, sysState
.name
, &tfid
.Fid
);
4837 } while (code
== ENOENT
&& Next_AtSys(avc
, areq
, &sysState
));
4838 ReleaseReadLock(&tdc
->lock
);
4839 afs_PutDCache(tdc
); /* we're done with the data */
4840 bufp
= sysState
.name
;
4844 tfid
.Cell
= avc
->f
.fid
.Cell
;
4845 tfid
.Fid
.Volume
= avc
->f
.fid
.Fid
.Volume
;
4846 if (!tfid
.Fid
.Unique
&& (avc
->f
.states
& CForeign
)) {
4847 tvc
= afs_LookupVCache(&tfid
, areq
, NULL
, avc
, bufp
);
4849 tvc
= afs_GetVCache(&tfid
, areq
, NULL
, NULL
);
4855 if (tvc
->mvstat
!= AFS_MVSTAT_MTPT
) {
4860 ObtainWriteLock(&tvc
->lock
, 649);
4861 /* next reference will re-stat cache entry */
4862 afs_StaleVCacheFlags(tvc
, 0, CDirty
);
4863 /* now find the disk cache entries */
4864 afs_TryToSmush(tvc
, *acred
, 1);
4865 if (tvc
->linkData
&& !(tvc
->f
.states
& CCore
)) {
4866 afs_osi_Free(tvc
->linkData
, strlen(tvc
->linkData
) + 1);
4867 tvc
->linkData
= NULL
;
4869 ReleaseWriteLock(&tvc
->lock
);
4872 if (sysState
.allocked
)
4873 osi_FreeLargeSpace(bufp
);
4878 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
4882 * \param[in] ain the flags that control which stats to use
4883 * \param[out] aout not in use
4885 * \retval EACCES Error if the user doesn't have super-user credentials
4886 * \retval EINVAL Error if the flag input is too long
4889 * either enable process RPCStats, disable process RPCStats,
4890 * or clear the process RPCStats
4892 DECL_PIOCTL(PRxStatProc
)
4896 if (!afs_osi_suser(*acred
))
4899 if (afs_pd_getInt(ain
, &flags
) != 0)
4902 if (!(flags
& AFSCALL_RXSTATS_MASK
) || (flags
& ~AFSCALL_RXSTATS_MASK
))
4905 if (flags
& AFSCALL_RXSTATS_ENABLE
) {
4906 rx_enableProcessRPCStats();
4908 if (flags
& AFSCALL_RXSTATS_DISABLE
) {
4909 rx_disableProcessRPCStats();
4911 if (flags
& AFSCALL_RXSTATS_CLEAR
) {
4912 rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL
);
4919 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
4923 * \param[in] ain the flags that control which statistics to use
4924 * \param[out] aout not in use
4926 * \retval EACCES Error if the user doesn't have super-user credentials
4927 * \retval EINVAL Error if the flag input is too long
4930 * either enable peer RPCStatws, disable peer RPCStats,
4931 * or clear the peer RPCStats
4933 DECL_PIOCTL(PRxStatPeer
)
4937 if (!afs_osi_suser(*acred
))
4940 if (afs_pd_getInt(ain
, &flags
) != 0)
4943 if (!(flags
& AFSCALL_RXSTATS_MASK
) || (flags
& ~AFSCALL_RXSTATS_MASK
))
4946 if (flags
& AFSCALL_RXSTATS_ENABLE
) {
4947 rx_enablePeerRPCStats();
4949 if (flags
& AFSCALL_RXSTATS_DISABLE
) {
4950 rx_disablePeerRPCStats();
4952 if (flags
& AFSCALL_RXSTATS_CLEAR
) {
4953 rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL
);
4958 DECL_PIOCTL(PPrefetchFromTape
)
4962 struct afs_conn
*tc
;
4963 struct rx_call
*tcall
;
4964 struct AFSVolSync tsync
;
4965 struct AFSFetchStatus OutStatus
;
4966 struct AFSCallBack CallBack
;
4967 struct VenusFid tfid
;
4970 struct rx_connection
*rxconn
;
4972 AFS_STATCNT(PPrefetchFromTape
);
4976 Fid
= afs_pd_inline(ain
, sizeof(struct AFSFid
));
4978 Fid
= &avc
->f
.fid
.Fid
;
4980 tfid
.Cell
= avc
->f
.fid
.Cell
;
4981 tfid
.Fid
.Volume
= Fid
->Volume
;
4982 tfid
.Fid
.Vnode
= Fid
->Vnode
;
4983 tfid
.Fid
.Unique
= Fid
->Unique
;
4985 tvc
= afs_GetVCache(&tfid
, areq
, NULL
, NULL
);
4987 afs_Trace3(afs_iclSetp
, CM_TRACE_PREFETCHCMD
, ICL_TYPE_POINTER
, tvc
,
4988 ICL_TYPE_FID
, &tfid
, ICL_TYPE_FID
, &avc
->f
.fid
);
4991 afs_Trace3(afs_iclSetp
, CM_TRACE_PREFETCHCMD
, ICL_TYPE_POINTER
, tvc
,
4992 ICL_TYPE_FID
, &tfid
, ICL_TYPE_FID
, &tvc
->f
.fid
);
4995 tc
= afs_Conn(&tvc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
4999 tcall
= rx_NewCall(rxconn
);
5001 StartRXAFS_FetchData(tcall
, (struct AFSFid
*)&tvc
->f
.fid
.Fid
, 0,
5004 rx_Read(tcall
, (char *)&outval
, sizeof(afs_int32
));
5006 EndRXAFS_FetchData(tcall
, &OutStatus
, &CallBack
, &tsync
);
5008 code
= rx_EndCall(tcall
, code
);
5012 } while (afs_Analyze
5013 (tc
, rxconn
, code
, &tvc
->f
.fid
, areq
, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS
,
5014 SHARED_LOCK
, NULL
));
5015 /* This call is done only to have the callback things handled correctly */
5016 afs_FetchStatus(tvc
, &tfid
, areq
, &OutStatus
);
5022 return afs_pd_putInt(aout
, outval
);
5028 struct afs_conn
*tc
;
5030 struct FsCmdInputs
*Inputs
;
5031 struct FsCmdOutputs
*Outputs
;
5032 struct VenusFid tfid
;
5034 struct rx_connection
*rxconn
;
5039 Inputs
= afs_pd_inline(ain
, sizeof(*Inputs
));
5043 Outputs
= afs_pd_inline(aout
, sizeof(*Outputs
));
5044 if (Outputs
== NULL
)
5049 Fid
= &avc
->f
.fid
.Fid
;
5051 tfid
.Cell
= avc
->f
.fid
.Cell
;
5052 tfid
.Fid
.Volume
= Fid
->Volume
;
5053 tfid
.Fid
.Vnode
= Fid
->Vnode
;
5054 tfid
.Fid
.Unique
= Fid
->Unique
;
5056 tvc
= afs_GetVCache(&tfid
, areq
, NULL
, NULL
);
5057 afs_Trace3(afs_iclSetp
, CM_TRACE_RESIDCMD
, ICL_TYPE_POINTER
, tvc
,
5058 ICL_TYPE_INT32
, Inputs
->command
, ICL_TYPE_FID
, &tfid
);
5062 if (Inputs
->command
) {
5064 tc
= afs_Conn(&tvc
->f
.fid
, areq
, SHARED_LOCK
, &rxconn
);
5068 RXAFS_FsCmd(rxconn
, Fid
, Inputs
, Outputs
);
5072 } while (afs_Analyze
5073 (tc
, rxconn
, code
, &tvc
->f
.fid
, areq
,
5074 AFS_STATS_FS_RPCIDX_RESIDENCYRPCS
, SHARED_LOCK
, NULL
));
5075 /* This call is done to have the callback things handled correctly */
5076 afs_FetchStatus(tvc
, &tfid
, areq
, &Outputs
->status
);
5077 } else { /* just a status request, return also link data */
5079 Outputs
->code
= afs_FetchStatus(tvc
, &tfid
, areq
, &Outputs
->status
);
5080 Outputs
->chars
[0] = 0;
5081 if (vType(tvc
) == VLNK
) {
5082 ObtainWriteLock(&tvc
->lock
, 555);
5083 if (afs_HandleLink(tvc
, areq
) == 0)
5084 strncpy((char *)&Outputs
->chars
, tvc
->linkData
, MAXCMDCHARS
);
5085 ReleaseWriteLock(&tvc
->lock
);
5094 DECL_PIOCTL(PNewUuid
)
5096 /*AFS_STATCNT(PNewUuid); */
5097 if (!afs_resourceinit_flag
) /* afs deamons havn't started yet */
5098 return EIO
; /* Inappropriate ioctl for device */
5100 if (!afs_osi_suser(*acred
))
5103 ObtainWriteLock(&afs_xinterface
, 555);
5104 afs_uuid_create(&afs_cb_interface
.uuid
);
5105 ReleaseWriteLock(&afs_xinterface
);
5106 ForceAllNewConnections();
5110 #if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
5112 DECL_PIOCTL(PSetCachingThreshold
)
5114 afs_int32 getting
= 1;
5115 afs_int32 setting
= 1;
5116 afs_int32 threshold
= AFS_CACHE_BYPASS_DISABLED
;
5118 if (afs_pd_getInt(ain
, &threshold
) != 0)
5124 if (setting
== 0 && getting
== 0)
5128 * If setting, set first, and return the value now in effect
5131 if (!afs_osi_suser(*acred
))
5133 cache_bypass_threshold
= threshold
;
5134 afs_warn("Cache Bypass Threshold set to: %d\n", threshold
);
5135 /* TODO: move to separate pioctl, or enhance pioctl */
5136 if (threshold
== AFS_CACHE_BYPASS_DISABLED
)
5137 cache_bypass_strategy
= NEVER_BYPASS_CACHE
;
5138 else if (!threshold
)
5139 cache_bypass_strategy
= ALWAYS_BYPASS_CACHE
;
5141 cache_bypass_strategy
= LARGE_FILES_BYPASS_CACHE
;
5144 /* Return the current size threshold */
5146 return afs_pd_putInt(aout
, cache_bypass_threshold
);
5151 #endif /* defined(AFS_CACHE_BYPASS) */
5153 DECL_PIOCTL(PCallBackAddr
)
5160 struct afs_conn
*tc
;
5161 afs_int32 i
, j
, addr
;
5162 struct unixuser
*tu
;
5163 struct srvAddr
**addrs
;
5164 struct rx_connection
*rxconn
;
5166 /*AFS_STATCNT(PCallBackAddr); */
5167 if (!afs_resourceinit_flag
) /* afs deamons havn't started yet */
5168 return EIO
; /* Inappropriate ioctl for device */
5170 if (!afs_osi_suser(acred
))
5173 if (afs_pd_getInt(ain
, &addr
) != 0)
5176 ObtainReadLock(&afs_xinterface
);
5177 for (i
= 0; (unsigned short)i
< afs_cb_interface
.numberOfInterfaces
; i
++) {
5178 if (afs_cb_interface
.addr_in
[i
] == addr
)
5182 ReleaseWriteLock(&afs_xinterface
);
5184 if (afs_cb_interface
.addr_in
[i
] != addr
)
5187 ObtainReadLock(&afs_xserver
); /* Necessary? */
5188 ObtainReadLock(&afs_xsrvAddr
);
5191 for (i
= 0; i
< NSERVERS
; i
++) {
5192 for (sa
= afs_srvAddrs
[i
]; sa
; sa
= sa
->next_bkt
) {
5197 addrs
= afs_osi_Alloc(srvAddrCount
* sizeof(*addrs
));
5198 osi_Assert(addrs
!= NULL
);
5200 for (i
= 0; i
< NSERVERS
; i
++) {
5201 for (sa
= afs_srvAddrs
[i
]; sa
; sa
= sa
->next_bkt
) {
5202 if (j
>= srvAddrCount
)
5208 ReleaseReadLock(&afs_xsrvAddr
);
5209 ReleaseReadLock(&afs_xserver
);
5211 for (i
= 0; i
< j
; i
++) {
5217 /* vlserver has no callback conn */
5218 if (sa
->sa_portal
== AFS_VLPORT
) {
5222 if (!ts
->cell
) /* not really an active server, anyway, it must */
5223 continue; /* have just been added by setsprefs */
5225 /* get a connection, even if host is down; bumps conn ref count */
5226 tu
= afs_GetUser(areq
->uid
, ts
->cell
->cellNum
, SHARED_LOCK
);
5227 tc
= afs_ConnBySA(sa
, ts
->cell
->fsport
, ts
->cell
->cellNum
, tu
,
5228 1 /*force */ , 1 /*create */ , SHARED_LOCK
, 0, &rxconn
);
5229 afs_PutUser(tu
, SHARED_LOCK
);
5233 if ((sa
->sa_flags
& SRVADDR_ISDOWN
) || afs_HaveCallBacksFrom(ts
)) {
5234 if (sa
->sa_flags
& SRVADDR_ISDOWN
) {
5235 rx_SetConnDeadTime(rxconn
, 3);
5237 #ifdef RX_ENABLE_LOCKS
5239 #endif /* RX_ENABLE_LOCKS */
5240 code
= RXAFS_CallBackRxConnAddr(rxconn
, &addr
);
5241 #ifdef RX_ENABLE_LOCKS
5243 #endif /* RX_ENABLE_LOCKS */
5245 afs_PutConn(tc
, rxconn
, SHARED_LOCK
); /* done with it now */
5246 } /* Outer loop over addrs */
5247 #endif /* UKERNEL */
5251 DECL_PIOCTL(PDiscon
)
5253 static afs_int32 mode
= 1; /* Start up in 'off' */
5254 afs_int32 force
= 0;
5257 struct vrequest lreq
;
5259 if (afs_pd_getBytes(ain
, &flags
, 4) == 0) {
5260 if (!afs_osi_suser(*acred
))
5264 mode
= flags
[0] - 1;
5266 afs_ConflictPolicy
= flags
[1] - 1;
5270 /* Fake InitReq support for UID override */
5271 memset(&lreq
, 0, sizeof(lreq
));
5272 lreq
.uid
= flags
[3];
5273 areq
= &lreq
; /* override areq we got */
5277 * All of these numbers are hard coded in fs.c. If they
5278 * change here, they should change there and vice versa
5281 case 0: /* Disconnect ("offline" mode), breaking all callbacks */
5282 if (!AFS_IS_DISCONNECTED
) {
5283 ObtainWriteLock(&afs_discon_lock
, 999);
5284 afs_DisconGiveUpCallbacks();
5285 afs_RemoveAllConns();
5286 afs_is_disconnected
= 1;
5287 afs_is_discon_rw
= 1;
5288 ReleaseWriteLock(&afs_discon_lock
);
5291 case 1: /* Fully connected, ("online" mode). */
5292 ObtainWriteLock(&afs_discon_lock
, 998);
5295 afs_MarkAllServersUp();
5296 code
= afs_ResyncDisconFiles(areq
, *acred
);
5299 if (code
&& !force
) {
5300 afs_warnuser("Files not synchronized properly, still in discon state. \n"
5301 "Please retry or use \"force\".\n");
5305 afs_DisconDiscardAll(*acred
);
5307 afs_ClearAllStatdFlag();
5308 afs_is_disconnected
= 0;
5309 afs_is_discon_rw
= 0;
5310 afs_warnuser("\nSync succeeded. You are back online.\n");
5313 ReleaseWriteLock(&afs_discon_lock
);
5325 return afs_pd_putInt(aout
, mode
);
5328 #define MAX_PIOCTL_TOKENS 10
5330 DECL_PIOCTL(PSetTokens2
)
5333 int i
, cellNum
, primaryFlag
;
5335 struct unixuser
*tu
;
5336 struct vrequest
*treq
= NULL
;
5337 struct ktc_setTokenData tokenSet
;
5338 struct ktc_tokenUnion decodedToken
;
5340 memset(&tokenSet
, 0, sizeof(tokenSet
));
5342 AFS_STATCNT(PSetTokens2
);
5343 if (!afs_resourceinit_flag
)
5346 afs_pd_xdrStart(ain
, &xdrs
, XDR_DECODE
);
5348 if (!xdr_ktc_setTokenData(&xdrs
, &tokenSet
)) {
5349 afs_pd_xdrEnd(ain
, &xdrs
);
5353 afs_pd_xdrEnd(ain
, &xdrs
);
5355 /* We limit each PAG to 10 tokens to prevent a malicous (or runaway)
5356 * process from using up the whole of the kernel memory by allocating
5359 if (tokenSet
.tokens
.tokens_len
> MAX_PIOCTL_TOKENS
) {
5360 xdr_free((xdrproc_t
) xdr_ktc_setTokenData
, &tokenSet
);
5364 code
= _settok_tokenCell(tokenSet
.cell
, &cellNum
, &primaryFlag
);
5366 xdr_free((xdrproc_t
) xdr_ktc_setTokenData
, &tokenSet
);
5370 if (tokenSet
.flags
& AFSTOKEN_EX_SETPAG
) {
5371 #if defined(AFS_LINUX26_ENV)
5372 afs_ucred_t
*old_cred
= *acred
;
5374 if (_settok_setParentPag(acred
) == 0) {
5375 #if defined(AFS_LINUX26_ENV)
5376 /* setpag() may have changed our credentials */
5380 code
= afs_CreateReq(&treq
, *acred
);
5382 xdr_free((xdrproc_t
) xdr_ktc_setTokenData
, &tokenSet
);
5389 tu
= afs_GetUser(areq
->uid
, cellNum
, WRITE_LOCK
);
5390 /* Free any tokens that we've already got */
5391 afs_FreeTokens(&tu
->tokens
);
5393 /* Iterate across the set of tokens we've received, and stuff them
5394 * into this user's tokenJar
5396 for (i
=0; i
< tokenSet
.tokens
.tokens_len
; i
++) {
5397 xdrmem_create(&xdrs
,
5398 tokenSet
.tokens
.tokens_val
[i
].token_opaque_val
,
5399 tokenSet
.tokens
.tokens_val
[i
].token_opaque_len
,
5402 memset(&decodedToken
, 0, sizeof(decodedToken
));
5403 if (!xdr_ktc_tokenUnion(&xdrs
, &decodedToken
)) {
5411 afs_AddTokenFromPioctl(&tu
->tokens
, &decodedToken
);
5412 /* This is untidy - the old token interface supported passing
5413 * the primaryFlag as part of the token interface. Current
5414 * OpenAFS userland never sets this, but it's specified as being
5415 * part of the XG interface, so we should probably still support
5416 * it. Rather than add it to our AddToken interface, just handle
5419 if (decodedToken
.at_type
== AFSTOKEN_UNION_KAD
) {
5420 if (decodedToken
.ktc_tokenUnion_u
.at_kad
.rk_primary_flag
)
5424 /* XXX - We should think more about destruction here. It's likely that
5425 * there is key material in what we're about to throw away, which
5426 * we really should zero out before giving back to the allocator */
5427 xdr_free((xdrproc_t
) xdr_ktc_tokenUnion
, &decodedToken
);
5430 tu
->states
|= UHasTokens
;
5431 tu
->states
&= ~UTokensBad
;
5432 afs_SetPrimary(tu
, primaryFlag
);
5433 tu
->tokenTime
= osi_Time();
5435 xdr_free((xdrproc_t
) xdr_ktc_setTokenData
, &tokenSet
);
5438 afs_ResetUserConns(tu
);
5439 afs_PutUser(tu
, WRITE_LOCK
);
5440 afs_DestroyReq(treq
);
5446 * VIOC_GETTOK2 (7) - Return a user's nth token, or token for a cell by
5451 * \param[in] ain EITHER a string cellname
5452 * OR an integer 'iterator' to specify the nth
5455 * \param[out] aout XDR-encoded tokens from the user's tokenJar
5457 * \retval EINVAL invalid input (bad integer, or invalid string)
5458 * unable to extract token(s)
5459 * \retval ENOMEM insufficient memory (returned from called routines)
5460 * \retval EDOM (integer) request was out of bounds or the user has no tokens
5461 * \retval ENOTCONN user found but has no valid token(s)
5462 * \retval E2BIG token(s) do not fit in the output buffer
5465 DECL_PIOCTL(PGetTokens2
)
5467 struct cell
*cell
= NULL
;
5468 struct unixuser
*tu
= NULL
;
5470 char *cellName
= NULL
;
5473 int integer_in
= 1; /* assume integer input */
5476 struct ktc_setTokenData tokenSet
;
5478 AFS_STATCNT(PGetTokens
);
5479 if (!afs_resourceinit_flag
)
5482 memset(&tokenSet
, 0, sizeof(tokenSet
));
5484 /* No input data - return tokens for primary cell */
5485 /* 4 octets of data is PROBABLY an iterator count */
5486 /* Otherwise, treat as string & return tokens for that cell name */
5488 if (afs_pd_remaining(ain
) == sizeof(afs_int32
)) {
5489 char *scratch
= afs_pd_where(ain
);
5491 if (scratch
[3] == '\0' && strlen(scratch
) == 3)
5498 /* The misleadingly-named getNthCell actually return the nth valid
5499 * token found for the specified user; there can never be a gap
5500 * in the ordinals at this level.
5502 if (afs_pd_getInt(ain
, &iterator
) != 0)
5504 tu
= getNthCell(areq
->uid
, iterator
);
5506 if (afs_pd_remaining(ain
) > 0) {
5507 if (afs_pd_getStringPtr(ain
, &cellName
) != 0)
5512 code
= _settok_tokenCell(cellName
, &cellNum
, NULL
);
5515 tu
= afs_FindUser(areq
->uid
, cellNum
, READ_LOCK
);
5522 if (!(tu
->states
& UHasTokens
)
5523 || !afs_HasValidTokens(tu
->tokens
, now
)) {
5524 tu
->states
|= (UTokensBad
| UNeedsReset
);
5525 afs_PutUser(tu
, READ_LOCK
);
5529 code
= afs_ExtractTokensForPioctl(tu
->tokens
, now
, &tokenSet
);
5533 cell
= afs_GetCell(tu
->cell
, READ_LOCK
);
5534 tokenSet
.cell
= cell
->cellName
;
5535 afs_pd_xdrStart(aout
, &xdrs
, XDR_ENCODE
);
5536 if (!xdr_ktc_setTokenData(&xdrs
, &tokenSet
)) {
5540 afs_pd_xdrEnd(aout
, &xdrs
);
5543 tokenSet
.cell
= NULL
;
5546 afs_PutUser(tu
, READ_LOCK
);
5548 afs_PutCell(cell
, READ_LOCK
);
5549 xdr_free((xdrproc_t
)xdr_ktc_setTokenData
, &tokenSet
);
5554 DECL_PIOCTL(PNFSNukeCreds
)
5558 struct unixuser
*tu
;
5560 AFS_STATCNT(PUnlog
);
5561 if (!afs_resourceinit_flag
) /* afs daemons haven't started yet */
5562 return EIO
; /* Inappropriate ioctl for device */
5564 if (afs_pd_getUint(ain
, &addr
) != 0)
5567 if (afs_cr_gid(*acred
) == RMTUSER_REQ_PRIV
&& !addr
) {
5568 tu
= afs_GetUser(areq
->uid
, -1, SHARED_LOCK
);
5569 if (!tu
->exporter
|| !(addr
= EXP_GETHOST(tu
->exporter
))) {
5570 afs_PutUser(tu
, SHARED_LOCK
);
5573 afs_PutUser(tu
, SHARED_LOCK
);
5574 } else if (!afs_osi_suser(acred
)) {
5578 ObtainWriteLock(&afs_xuser
, 227);
5579 for (i
= 0; i
< NUSERS
; i
++) {
5580 for (tu
= afs_users
[i
]; tu
; tu
= tu
->next
) {
5581 if (tu
->exporter
&& EXP_CHECKHOST(tu
->exporter
, addr
)) {
5583 ReleaseWriteLock(&afs_xuser
);
5585 afs_LockUser(tu
, WRITE_LOCK
, 367);
5587 tu
->states
&= ~UHasTokens
;
5588 afs_FreeTokens(&tu
->tokens
);
5589 afs_ResetUserConns(tu
);
5590 afs_PutUser(tu
, WRITE_LOCK
);
5591 ObtainWriteLock(&afs_xuser
, 228);
5593 /* set the expire times to 0, causes
5594 * afs_GCUserData to remove this entry
5597 #endif /* UKERNEL */
5601 ReleaseWriteLock(&afs_xuser
);