369d35b1a54e9ab82f0cb634a389f43e5822bfde
[openafs.git] / src / afs / SOLARIS / osi_vfsops.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * osi_vfsops.c for SOLARIS
12  */
13 #include <afsconfig.h>
14 #include "afs/param.h"
15
16
17 #include "afs/sysincludes.h"    /* Standard vendor system headers */
18 #include "afsincludes.h"        /* Afs-based standard headers */
19 #include "afs/afs_stats.h"      /* statistics stuff */
20 #include "h/modctl.h"
21 #include "h/syscall.h"
22 #if defined(AFS_SUN511_ENV)
23 #include <sys/vfs_opreg.h>
24 #endif
25 #include <sys/kobj.h>
26
27 #ifdef AFS_SUN58_ENV
28 # include <sys/mount.h>
29 #endif
30
31 struct vfs *afs_globalVFS = 0;
32 struct vcache *afs_globalVp = 0;
33
34 #if defined(AFS_SUN57_64BIT_ENV)
35 extern struct sysent sysent32[];
36 #endif
37
38 int afsfstype = 0;
39
40 int
41 afs_mount(struct vfs *afsp, struct vnode *amvp, struct mounta *uap,
42           afs_ucred_t *credp)
43 {
44
45     AFS_GLOCK();
46
47     AFS_STATCNT(afs_mount);
48
49 #if defined(AFS_SUN510_ENV)
50     if (secpolicy_fs_mount(credp, amvp, afsp) != 0) {
51 #else
52     if (!afs_osi_suser(credp)) {
53 #endif
54         AFS_GUNLOCK();
55         return (EPERM);
56     }
57     afsp->vfs_fstype = afsfstype;
58
59     if (afs_globalVFS) {        /* Don't allow remounts. */
60         AFS_GUNLOCK();
61         return (EBUSY);
62     }
63
64     afs_globalVFS = afsp;
65     afsp->vfs_bsize = 8192;
66     afsp->vfs_fsid.val[0] = AFS_VFSMAGIC;       /* magic */
67     afsp->vfs_fsid.val[1] = AFS_VFSFSID;
68     afsp->vfs_dev = AFS_VFSMAGIC;
69
70     AFS_GUNLOCK();
71     return 0;
72 }
73
74 static void
75 afs_freevfs(void)
76 {
77     int i;
78     struct vcache *vc, *nvc;
79     extern struct vcache *afs_vhashT[VCSIZE];
80
81     afs_globalVFS = 0;
82
83     /* free mappings for all vcaches */
84     for (i = 0; i < VCSIZE; i++) {
85         for (vc = afs_vhashT[i]; vc; vc = nvc) {
86             int fv_slept;
87             nvc = vc->hnext;
88             if (afs_FlushVCache(vc, &fv_slept)) {
89                 afs_warn("afs_FlushVCache failed on 0x%llx\n",
90                          (unsigned long long)vc);
91             }
92         }
93     }
94
95     afs_shutdown();
96 }
97
98 #if defined(AFS_SUN58_ENV)
99 int
100 afs_unmount(struct vfs *afsp, int flag, afs_ucred_t *credp)
101 #else
102 int
103 afs_unmount(struct vfs *afsp, afs_ucred_t *credp)
104 #endif
105 {
106     struct vcache *rootvp = NULL;
107
108     AFS_GLOCK();
109     AFS_STATCNT(afs_unmount);
110
111 #if defined(AFS_SUN510_ENV)
112     if (secpolicy_fs_unmount(credp, afsp) != 0) {
113 #else
114     if (!afs_osi_suser(credp)) {
115 #endif
116         AFS_GUNLOCK();
117         return (EPERM);
118     }
119
120 #ifdef AFS_SUN58_ENV
121     if (flag & MS_FORCE) {
122         AFS_GUNLOCK();
123         return ENOTSUP;
124     }
125
126     /* We should have one reference from the caller, and one reference for the
127      * root vnode; any more and someone is still referencing something */
128     if (afsp->vfs_count > 2) {
129         AFS_GUNLOCK();
130         return EBUSY;
131     }
132
133     /* The root vnode should have one ref for the mount; any more, and someone
134      * else is using the root vnode */
135     if (afs_globalVp && VREFCOUNT_GT(afs_globalVp, 1)) {
136         AFS_GUNLOCK();
137         return EBUSY;
138     }
139
140     afsp->vfs_flag |= VFS_UNMOUNTED;
141 #endif /* AFS_SUN58_ENV */
142
143     /* release the root vnode, which should be the last reference to us
144      * besides the caller of afs_unmount */
145     rootvp = afs_globalVp;
146     afs_globalVp = NULL;
147     AFS_RELE(rootvp);
148
149 #ifndef AFS_SUN58_ENV
150     /* shutdown now, since gafs_freevfs() will not be called */
151     afs_freevfs();
152 #endif /* !AFS_SUN58_ENV */
153
154     AFS_GUNLOCK();
155     return 0;
156 }
157
158 #ifdef AFS_SUN58_ENV
159 void
160 gafs_freevfs(struct vfs *afsp)
161 {
162     AFS_GLOCK();
163
164     afs_freevfs();
165
166     AFS_GUNLOCK();
167 }
168 #endif /* AFS_SUN58_ENV */
169
170 int
171 afs_root(struct vfs *afsp, struct vnode **avpp)
172 {
173     afs_int32 code = 0;
174     struct vrequest treq;
175     struct vcache *tvp = 0;
176     struct vcache *gvp;
177     struct proc *proc = ttoproc(curthread);
178     struct vnode *vp = afsp->vfs_vnodecovered;
179     int locked = 0;
180
181     /* Potential deadlock:
182      * afs_root is called with the Vnode's v_lock locked. Set VVFSLOCK
183      * and drop the v_lock if we need to make an RPC to complete this
184      * request. There used to be a deadlock on the global lock until
185      * we stopped calling iget while holding the global lock.
186      */
187
188     AFS_GLOCK();
189
190     AFS_STATCNT(afs_root);
191
192 again:
193     if (afs_globalVp && (afs_globalVp->f.states & CStatd)) {
194         tvp = afs_globalVp;
195     } else {
196         if (MUTEX_HELD(&vp->v_lock)) {
197             vp->v_flag |= VVFSLOCK;
198             locked = 1;
199             mutex_exit(&vp->v_lock);
200         }
201
202         if (afs_globalVp) {
203             gvp = afs_globalVp;
204             afs_globalVp = NULL;
205             afs_PutVCache(gvp);
206         }
207
208         if (!(code = afs_InitReq(&treq, proc->p_cred))
209             && !(code = afs_CheckInit())) {
210             tvp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
211             /* we really want this to stay around */
212             if (tvp) {
213                 if (afs_globalVp) {
214                     /* someone else got there before us! */
215                     afs_PutVCache(tvp);
216                     tvp = 0;
217                     goto again;
218                 }
219                 afs_globalVp = tvp;
220             } else
221                 code = ENOENT;
222         }
223     }
224     if (tvp) {
225         AFS_FAST_HOLD(tvp);
226         mutex_enter(&AFSTOV(tvp)->v_lock);
227         AFSTOV(tvp)->v_flag |= VROOT;
228         mutex_exit(&AFSTOV(tvp)->v_lock);
229
230         afs_globalVFS = afsp;
231         *avpp = AFSTOV(tvp);
232     }
233
234     afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, *avpp,
235                ICL_TYPE_INT32, code);
236
237     AFS_GUNLOCK();
238     if (locked) {
239         mutex_enter(&vp->v_lock);
240         vp->v_flag &= ~VVFSLOCK;
241         if (vp->v_flag & VVFSWAIT) {
242             vp->v_flag &= ~VVFSWAIT;
243             cv_broadcast(&vp->v_cv);
244         }
245     }
246
247     return code;
248 }
249
250 #ifdef AFS_SUN56_ENV
251 int
252 afs_statvfs(struct vfs *afsp, struct statvfs64 *abp)
253 #else
254 int
255 afs_statvfs(struct vfs *afsp, struct statvfs *abp)
256 #endif
257 {
258     AFS_GLOCK();
259
260     AFS_STATCNT(afs_statfs);
261
262     abp->f_frsize = 1024;
263     abp->f_favail = 9000000;
264     abp->f_bsize = afsp->vfs_bsize;
265     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
266         abp->f_ffree = 9000000;
267     abp->f_fsid = (AFS_VFSMAGIC << 16) || AFS_VFSFSID;
268
269     AFS_GUNLOCK();
270     return 0;
271 }
272
273 int
274 afs_sync(struct vfs *afsp, short flags, afs_ucred_t *credp)
275 {
276     return 0;
277 }
278
279 int
280 afs_vget(struct vfs *afsp, struct vnode **avcp, struct fid *fidp)
281 {
282     cred_t *credp = CRED();
283     struct vrequest treq;
284     int code;
285
286     AFS_GLOCK();
287
288     AFS_STATCNT(afs_vget);
289
290     *avcp = NULL;
291     if (!(code = afs_InitReq(&treq, credp))) {
292         code = afs_osi_vget((struct vcache **)avcp, fidp, &treq);
293     }
294
295     afs_Trace3(afs_iclSetp, CM_TRACE_VGET, ICL_TYPE_POINTER, *avcp,
296                ICL_TYPE_INT32, treq.uid, ICL_TYPE_FID, fidp);
297     code = afs_CheckCode(code, &treq, 42);
298
299     AFS_GUNLOCK();
300     return code;
301 }
302
303 /* This is only called by vfs_mount when afs is going to be mounted as root.
304  * Since we don't support diskless clients we shouldn't come here.
305  */
306 int afsmountroot = 0;
307 afs_mountroot(struct vfs *afsp, whymountroot_t why)
308 {
309     AFS_GLOCK();
310     AFS_STATCNT(afs_mountroot);
311     afsmountroot++;
312     AFS_GUNLOCK();
313     return EINVAL;
314 }
315
316 /* afs_swapvp is called to setup swapping over the net for diskless clients.
317  * Again not for us.
318  */
319 int afsswapvp = 0;
320 afs_swapvp(struct vfs *afsp, struct vnode **avpp, char *nm)
321 {
322     AFS_GLOCK();
323     AFS_STATCNT(afs_swapvp);
324     afsswapvp++;
325     AFS_GUNLOCK();
326     return EINVAL;
327 }
328
329
330 #if defined(AFS_SUN511_ENV)
331 /* The following list must always be NULL-terminated */
332 static const fs_operation_def_t afs_vfsops_template[] = {
333     VFSNAME_MOUNT,              { .vfs_mount = afs_mount },
334     VFSNAME_UNMOUNT,            { .vfs_unmount = afs_unmount },
335     VFSNAME_ROOT,               { .vfs_root = afs_root },
336     VFSNAME_STATVFS,            { .vfs_statvfs = afs_statvfs },
337     VFSNAME_SYNC,               { .vfs_sync = afs_sync },
338     VFSNAME_VGET,               { .vfs_vget = afs_vget },
339     VFSNAME_MOUNTROOT,          { .vfs_mountroot = afs_mountroot },
340     VFSNAME_FREEVFS,            { .vfs_freevfs = gafs_freevfs },
341     NULL,                       NULL
342 };
343 struct vfsops *afs_vfsopsp;
344 #elif defined(AFS_SUN510_ENV)
345 /* The following list must always be NULL-terminated */
346 const fs_operation_def_t afs_vfsops_template[] = {
347     VFSNAME_MOUNT,              afs_mount,
348     VFSNAME_UNMOUNT,            afs_unmount,
349     VFSNAME_ROOT,               afs_root,
350     VFSNAME_STATVFS,            afs_statvfs,
351     VFSNAME_SYNC,               afs_sync,
352     VFSNAME_VGET,               afs_vget,
353     VFSNAME_MOUNTROOT,          afs_mountroot,
354     VFSNAME_FREEVFS,            gafs_freevfs,
355     NULL,                       NULL
356 };
357 struct vfsops *afs_vfsopsp;
358 #else
359 struct vfsops Afs_vfsops = {
360     afs_mount,
361     afs_unmount,
362     afs_root,
363     afs_statvfs,
364     afs_sync,
365     afs_vget,
366     afs_mountroot,
367     afs_swapvp,
368 #if defined(AFS_SUN58_ENV)
369     gafs_freevfs,
370 #endif
371 };
372 #endif
373
374
375 /*
376  * afsinit - intialize VFS
377  */
378 int (*ufs_iallocp) ();
379 void (*ufs_iupdatp) ();
380 int (*ufs_igetp) ();
381 void (*ufs_itimes_nolockp) ();
382
383 int (*afs_orig_ioctl) (), (*afs_orig_ioctl32) ();
384 int (*afs_orig_setgroups) (), (*afs_orig_setgroups32) ();
385
386 #ifndef AFS_SUN510_ENV
387 struct ill_s *ill_g_headp = 0;
388 #endif
389
390 int afs_sinited = 0;
391
392 extern struct fs_operation_def afs_vnodeops_template[];
393
394 #if     !defined(AFS_NONFSTRANS)
395 int (*nfs_rfsdisptab_v2) ();
396 int (*nfs_rfsdisptab_v3) ();
397 int (*nfs_acldisptab_v2) ();
398 int (*nfs_acldisptab_v3) ();
399
400 int (*nfs_checkauth) ();
401 #endif
402
403 extern Afs_syscall();
404
405 static void *
406 do_mod_lookup(const char * mod, const char * sym)
407 {
408     void * ptr;
409
410     ptr = modlookup(mod, sym);
411     if (ptr == NULL) {
412         afs_warn("modlookup failed for symbol '%s' in module '%s'\n",
413                  sym, mod);
414     }
415
416     return ptr;
417 }
418
419 #ifdef AFS_SUN510_ENV
420 afsinit(int fstype, char *dummy)
421 #else
422 afsinit(struct vfssw *vfsswp, int fstype)
423 #endif
424 {
425     extern int afs_xioctl();
426     extern int afs_xsetgroups();
427
428     AFS_STATCNT(afsinit);
429
430     afs_orig_setgroups = sysent[SYS_setgroups].sy_callc;
431     afs_orig_ioctl = sysent[SYS_ioctl].sy_call;
432     sysent[SYS_setgroups].sy_callc = afs_xsetgroups;
433     sysent[SYS_ioctl].sy_call = afs_xioctl;
434
435 #if defined(AFS_SUN57_64BIT_ENV)
436     afs_orig_setgroups32 = sysent32[SYS_setgroups].sy_callc;
437     afs_orig_ioctl32 = sysent32[SYS_ioctl].sy_call;
438     sysent32[SYS_setgroups].sy_callc = afs_xsetgroups;
439     sysent32[SYS_ioctl].sy_call = afs_xioctl;
440 #endif /* AFS_SUN57_64BIT_ENV */
441
442 #ifdef AFS_SUN510_ENV
443     vfs_setfsops(fstype, afs_vfsops_template, &afs_vfsopsp);
444     afsfstype = fstype;
445     vn_make_ops("afs", afs_vnodeops_template, &afs_ops);
446 #else /* !AFS_SUN510_ENV */
447     vfsswp->vsw_vfsops = &Afs_vfsops;
448     afsfstype = fstype;
449 #endif /* !AFS_SUN510_ENV */
450
451
452 #if !defined(AFS_NONFSTRANS)
453     nfs_rfsdisptab_v2 = (int (*)()) do_mod_lookup("nfssrv", "rfsdisptab_v2");
454     if (nfs_rfsdisptab_v2 != NULL) {
455         nfs_acldisptab_v2 = (int (*)()) do_mod_lookup("nfssrv", "acldisptab_v2");
456         if (nfs_acldisptab_v2 != NULL) {
457             afs_xlatorinit_v2(nfs_rfsdisptab_v2, nfs_acldisptab_v2);
458         }
459     }
460     nfs_rfsdisptab_v3 = (int (*)()) do_mod_lookup("nfssrv", "rfsdisptab_v3");
461     if (nfs_rfsdisptab_v3 != NULL) {
462         nfs_acldisptab_v3 = (int (*)()) do_mod_lookup("nfssrv", "acldisptab_v3");
463         if (nfs_acldisptab_v3 != NULL) {
464             afs_xlatorinit_v3(nfs_rfsdisptab_v3, nfs_acldisptab_v3);
465         }
466     }
467
468     nfs_checkauth = (int (*)()) do_mod_lookup("nfssrv", "checkauth");
469 #endif /* !AFS_NONFSTRANS */
470
471     ufs_iallocp = (int (*)()) do_mod_lookup("ufs", "ufs_ialloc");
472     ufs_iupdatp = (void (*)()) do_mod_lookup("ufs", "ufs_iupdat");
473     ufs_igetp = (int (*)()) do_mod_lookup("ufs", "ufs_iget");
474     ufs_itimes_nolockp = (void (*)()) do_mod_lookup("ufs", "ufs_itimes_nolock");
475
476     if (!ufs_iallocp || !ufs_iupdatp || !ufs_itimes_nolockp || !ufs_igetp) {
477         afs_warn("AFS to UFS mapping cannot be fully initialised\n");
478     }
479
480 #if !defined(AFS_SUN510_ENV)
481     ill_g_headp = (struct ill_s *) do_mod_lookup("ip", "ill_g_head");
482 #endif /* !AFS_SUN510_ENV */
483
484     afs_sinited = 1;
485     return 0;
486
487 }
488
489 #ifdef AFS_SUN510_ENV
490 #ifdef AFS_SUN511_ENV
491 static vfsdef_t afs_vfsdef = {
492     VFSDEF_VERSION,
493     "afs",
494     afsinit,
495     0,
496     NULL
497 };
498 #else
499 static struct vfsdef_v3 afs_vfsdef = {
500     VFSDEF_VERSION,
501     "afs",
502     afsinit,
503     0
504 };
505 #endif
506 #else
507 static struct vfssw afs_vfw = {
508     "afs",
509     afsinit,
510     &Afs_vfsops,
511     0
512 };
513 #endif
514
515 static struct sysent afssysent = {
516     6,
517     0,
518     Afs_syscall
519 };
520
521 /* inter-module dependencies */
522 char _depends_on[] = "drv/ip drv/udp strmod/rpcmod";
523
524 /*
525  * Info/Structs to link the afs module into the kernel
526  */
527 extern struct mod_ops mod_fsops;
528 extern struct mod_ops mod_syscallops;
529
530 static struct modlfs afsmodlfs = {
531     &mod_fsops,
532     "afs filesystem",
533 #ifdef AFS_SUN510_ENV
534     &afs_vfsdef
535 #else
536     &afs_vfw
537 #endif
538 };
539
540 static struct modlsys afsmodlsys = {
541     &mod_syscallops,
542     "afs syscall interface",
543     &afssysent
544 };
545
546 /** The two structures afssysent32 and afsmodlsys32 are being added
547   * for supporting 32 bit syscalls. In Solaris 7 there are two system
548   * tables viz. sysent ans sysent32. 32 bit applications use sysent32.
549   * Since most of our user space binaries are going to be 32 bit
550   * we need to attach to sysent32 also. Note that the entry into AFS
551   * land still happens through Afs_syscall irrespective of whether we
552   * land here from sysent or sysent32
553   */
554
555 #if defined(AFS_SUN57_64BIT_ENV)
556 extern struct mod_ops mod_syscallops32;
557
558 static struct modlsys afsmodlsys32 = {
559     &mod_syscallops32,
560     "afs syscall interface(32 bit)",
561     &afssysent
562 };
563 #endif
564
565
566 static struct modlinkage afs_modlinkage = {
567     MODREV_1,
568     (void *)&afsmodlsys,
569 #ifdef AFS_SUN57_64BIT_ENV
570     (void *)&afsmodlsys32,
571 #endif
572     (void *)&afsmodlfs,
573     NULL
574 };
575
576 /** This is the function that modload calls when loading the afs kernel
577   * extensions. The solaris modload program searches for the _init
578   * function in a module and calls it when modloading
579   */
580
581 _init()
582 {
583     char *sysn, *mod_getsysname();
584     int code;
585     extern char *sysbind;
586     extern struct bind *sb_hashtab[];
587     struct modctl *mp = 0;
588
589     if (afs_sinited)
590         return EBUSY;
591
592     if ((!(mp = mod_find_by_filename("fs", "ufs"))
593          && !(mp = mod_find_by_filename(NULL, "/kernel/fs/ufs"))
594          && !(mp = mod_find_by_filename(NULL, "sys/ufs"))) || (mp
595                                                                && !mp->
596                                                                mod_installed))
597     {
598         printf
599             ("ufs module must be loaded before loading afs; use modload /kernel/fs/ufs\n");
600         return (ENOSYS);
601     }
602 #ifndef AFS_NONFSTRANS
603 #if     defined(AFS_SUN55_ENV)
604     if ((!(mp = mod_find_by_filename("misc", "nfssrv"))
605          && !(mp = mod_find_by_filename(NULL, NFSSRV))
606          && !(mp = mod_find_by_filename(NULL, NFSSRV_V9))
607          && !(mp = mod_find_by_filename(NULL, NFSSRV_AMD64))) || (mp
608                                                                && !mp->
609                                                                mod_installed))
610     {
611         printf
612             ("misc/nfssrv module must be loaded before loading afs with nfs-xlator\n");
613         return (ENOSYS);
614     }
615 #else /* !AFS_SUN55_ENV */
616 #if     defined(AFS_SUN52_ENV)
617     if ((!(mp = mod_find_by_filename("fs", "nfs"))
618          && !(mp = mod_find_by_filename(NULL, "/kernel/fs/nfs"))
619          && !(mp = mod_find_by_filename(NULL, "sys/nfs"))) || (mp
620                                                                && !mp->
621                                                                mod_installed))
622     {
623         printf
624             ("fs/nfs module must be loaded before loading afs with nfs-xlator\n");
625         return (ENOSYS);
626     }
627 #endif /* AFS_SUN52_ENV */
628 #endif /* AFS_SUN55_ENV */
629 #endif /* !AFS_NONFSTRANS */
630 #if !defined(AFS_SUN58_ENV)
631     /* 
632      * Re-read the /etc/name_to_sysnum file to make sure afs isn't added after
633      * reboot.  Ideally we would like to call modctl_read_sysbinding_file() but
634      * unfortunately in Solaris 2.2 it became a local function so we have to do
635      * the read_binding_file() direct call with the appropriate text file and
636      * system call hashtable.  make_syscallname actually copies "afs" to the
637      * proper slot entry and we also actually have to properly initialize the
638      * global sysent[AFS_SYSCALL] entry!
639      */
640 #ifdef  AFS_SUN53_ENV
641 #ifndef SYSBINDFILE
642 #define SYSBINDFILE     "/etc/name_to_sysnum"
643 #endif /* SYSBINDFILE */
644     read_binding_file(SYSBINDFILE, sb_hashtab);
645 #else /* !AFS_SUN53_ENV */
646     read_binding_file(sysbind, sb_hashtab);
647 #endif /* AFS_SUN53_ENV */
648     make_syscallname("afs", AFS_SYSCALL);
649
650     if (sysent[AFS_SYSCALL].sy_call == nosys) {
651         if ((sysn = mod_getsysname(AFS_SYSCALL)) != NULL) {
652             sysent[AFS_SYSCALL].sy_lock =
653                 (krwlock_t *) kobj_zalloc(sizeof(krwlock_t), KM_SLEEP);
654             rw_init(sysent[AFS_SYSCALL].sy_lock, "afs_syscall",
655 #ifdef AFS_SUN57_ENV
656                     RW_DEFAULT, NULL);
657 #else /* !AFS_SUN57_ENV */
658                     RW_DEFAULT, DEFAULT_WT);
659 #endif /* AFS_SUN57_ENV */
660         }
661     }
662 #endif /* !AFS_SUN58_ENV */
663
664     osi_Init();                 /* initialize global lock, etc */
665
666     code = mod_install(&afs_modlinkage);
667     return code;
668 }
669
670 _info(modp)
671      struct modinfo *modp;
672 {
673     int code;
674
675     code = mod_info(&afs_modlinkage, modp);
676     return code;
677 }
678
679 _fini()
680 {
681     int code;
682
683     if (afs_globalVFS)
684         return EBUSY;
685
686     if (afs_sinited) {
687         sysent[SYS_setgroups].sy_callc = afs_orig_setgroups;
688         sysent[SYS_ioctl].sy_call = afs_orig_ioctl;
689 #if defined(AFS_SUN57_64BIT_ENV)
690         sysent32[SYS_setgroups].sy_callc = afs_orig_setgroups32;
691         sysent32[SYS_ioctl].sy_call = afs_orig_ioctl32;
692 #endif
693     }
694     code = mod_remove(&afs_modlinkage);
695     return code;
696 }