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