Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / afs / SOLARIS / osi_vfsops.c
1 /* Copyright (C) 1995, 1998 Transarc Corporation - All rights reserved. */
2 /*
3  * (C) COPYRIGHT IBM CORPORATION 1987, 1988
4  * LICENSED MATERIALS - PROPERTY OF IBM
5  */
6 /*
7  * osi_vfsops.c for SOLARIS
8  */
9 #include "../afs/param.h"       /* Should be always first */
10 #include "../afs/sysincludes.h" /* Standard vendor system headers */
11 #include "../afs/afsincludes.h" /* Afs-based standard headers */
12 #include "../afs/afs_stats.h"   /* statistics stuff */
13 #include "../h/modctl.h"
14 #include "../h/syscall.h"
15 #include <sys/kobj.h>
16
17
18
19 struct vfs *afs_globalVFS = 0;
20 struct vcache *afs_globalVp = 0;
21
22 #if defined(AFS_SUN57_64BIT_ENV)
23 extern struct sysent sysent32[];
24 #endif
25
26 int afsfstype = 0;
27
28 int afs_mount(struct vfs *afsp, struct vnode *amvp, struct mounta *uap,
29           struct AFS_UCRED *credp)
30 {
31
32     AFS_GLOCK();
33
34     AFS_STATCNT(afs_mount);
35
36     if (!suser(credp))
37         return EPERM;
38     afsp->vfs_fstype = afsfstype;
39
40     if (afs_globalVFS) { /* Don't allow remounts. */
41         return EBUSY;
42     }
43
44     afs_globalVFS = afsp;
45     afsp->vfs_bsize = 8192;
46     afsp->vfs_fsid.val[0] = AFS_VFSMAGIC; /* magic */
47     afsp->vfs_fsid.val[1] = AFS_VFSFSID; 
48
49     AFS_GUNLOCK();
50     return 0;
51 }
52
53 int afs_unmount (struct vfs *afsp, struct AFS_UCRED *credp)
54 {
55     AFS_GLOCK();
56     AFS_STATCNT(afs_unmount);
57
58     if (!suser(credp))
59         return EPERM;
60     afs_globalVFS = 0;
61     afs_shutdown();
62
63     AFS_GUNLOCK();
64     return 0;
65 }
66
67 int afs_root (struct vfs *afsp, struct vnode **avpp)
68 {
69     register afs_int32 code = 0;
70     struct vrequest treq;
71     register struct vcache *tvp=0;
72     struct proc *proc = ttoproc(curthread);
73     struct vnode *vp = afsp->vfs_vnodecovered;
74     int locked = 0;
75
76     /* Potential deadlock:
77      * afs_root is called with the Vnode's v_lock locked. Set VVFSLOCK
78      * and drop the v_lock if we need to make an RPC to complete this
79      * request. There used to be a deadlock on the global lock until
80      * we stopped calling iget while holding the global lock.
81      */
82
83     AFS_GLOCK();
84
85     AFS_STATCNT(afs_root);
86
87     if (afs_globalVp && (afs_globalVp->states & CStatd)) {
88         tvp = afs_globalVp;
89     } else {
90         if (MUTEX_HELD(&vp->v_lock)) {
91             vp->v_flag |= VVFSLOCK;
92             locked = 1;
93             mutex_exit(&vp->v_lock);
94         }
95         if (!(code = afs_InitReq(&treq, proc->p_cred)) &&
96             !(code = afs_CheckInit())) {
97             tvp = afs_GetVCache(&afs_rootFid, &treq, (afs_int32 *)0,
98                                 (struct vcache*)0, WRITE_LOCK);
99             /* we really want this to stay around */
100             if (tvp) {
101                 afs_globalVp = tvp;
102             } else
103                 code = ENOENT;
104         }
105     }
106     if (tvp) {
107         VN_HOLD((struct vnode *)tvp);
108         mutex_enter(&(((struct vnode*)tvp)->v_lock));
109         tvp->v.v_flag |= VROOT;
110         mutex_exit(&(((struct vnode*)tvp)->v_lock));
111
112         afs_globalVFS = afsp;
113         *avpp = (struct vnode *) tvp;
114     }
115
116     afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, *avpp,
117                ICL_TYPE_INT32, code);
118
119     AFS_GUNLOCK();
120     if (locked) {
121         mutex_enter(&vp->v_lock);
122         vp->v_flag &= ~VVFSLOCK;
123         if (vp->v_flag & VVFSWAIT) {
124             vp->v_flag &= ~VVFSWAIT;
125             cv_broadcast(&vp->v_cv);
126         }
127     }
128
129     return code;
130 }
131
132 #ifdef AFS_SUN56_ENV
133 int afs_statvfs(struct vfs *afsp, struct statvfs64 *abp)
134 #else
135 int afs_statvfs(struct vfs *afsp, struct statvfs *abp)
136 #endif
137 {
138     AFS_GLOCK();
139
140     AFS_STATCNT(afs_statfs);
141
142     abp->f_frsize = 1024;
143     abp->f_favail =  9000000;
144     abp->f_bsize = afsp->vfs_bsize;
145     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
146         abp->f_ffree  = 9000000;
147     abp->f_fsid = (AFS_VFSMAGIC << 16) || AFS_VFSFSID;
148
149     AFS_GUNLOCK();
150     return 0;
151 }
152
153 int afs_sync(struct vfs *afsp, short flags, struct AFS_UCRED *credp)
154 {
155     return 0;
156 }
157
158 int afs_vget(struct vfs *afsp, struct vnode **avcp, struct fid *fidp)
159 {
160     cred_t *credp = CRED();
161     struct vrequest treq;
162     int code;
163
164     AFS_GLOCK();
165
166     AFS_STATCNT(afs_vget);
167
168     *avcp = NULL;
169     if (!(code = afs_InitReq(&treq, credp))) {
170         code = afs_osi_vget((struct vcache**)avcp, fidp, &treq);
171     }
172
173     afs_Trace3(afs_iclSetp, CM_TRACE_VGET, ICL_TYPE_POINTER, *avcp,
174                ICL_TYPE_INT32, treq.uid, ICL_TYPE_FID, fidp);
175     code = afs_CheckCode(code, &treq, 42);
176
177     AFS_GUNLOCK();
178     return code;
179 }
180
181 /* This is only called by vfs_mount when afs is going to be mounted as root.
182  * Since we don't support diskless clients we shouldn't come here.
183  */
184 int afsmountroot=0;
185 afs_mountroot(struct vfs *afsp, whymountroot_t why)
186 {
187     AFS_GLOCK();
188     AFS_STATCNT(afs_mountroot);
189     afsmountroot++;
190     AFS_GUNLOCK();
191     return EINVAL;
192 }
193
194 /* afs_swapvp is called to setup swapping over the net for diskless clients.
195  * Again not for us.
196  */
197 int afsswapvp=0;
198 afs_swapvp(struct vfs *afsp, struct vnode **avpp, char *nm)
199 {
200     AFS_GLOCK();
201     AFS_STATCNT(afs_swapvp);
202     afsswapvp++;
203     AFS_GUNLOCK();
204     return EINVAL;
205 }
206
207
208 struct vfsops Afs_vfsops = {
209     afs_mount,
210     afs_unmount,
211     afs_root,
212     afs_statvfs,
213     afs_sync,
214     afs_vget,
215     afs_mountroot,
216     afs_swapvp
217 };
218
219
220 /*
221  * afsinit - intialize VFS
222  */
223 void (*ufs_iputp)();
224 int (*ufs_iallocp)();
225 void (*ufs_iupdatp)();
226 int (*ufs_igetp)();
227
228 struct streamtab *udp_infop = 0;
229 struct ill_s *ill_g_headp = 0;
230
231 int afs_sinited = 0;
232
233 #if     !defined(AFS_NONFSTRANS)
234 int (*nfs_rfsdisptab_v2)();
235 int (*nfs_rfsdisptab_v3)();
236 int (*nfs_acldisptab_v2)();
237 int (*nfs_acldisptab_v3)();
238
239 int (*nfs_checkauth)();
240 #endif
241
242 extern Afs_syscall();
243
244 afsinit(struct vfssw *vfsswp, int fstype)
245 {
246     extern int afs_xioctl(), afs_xflock();
247     extern int afs_xsetgroups();
248
249     AFS_STATCNT(afsinit);
250
251     sysent[SYS_setgroups].sy_callc = afs_xsetgroups;
252     sysent[SYS_ioctl].sy_call = afs_xioctl;
253
254 #if defined(AFS_SUN57_64BIT_ENV)
255     sysent32[SYS_setgroups].sy_callc = afs_xsetgroups;
256     sysent32[SYS_ioctl].sy_call = afs_xioctl;
257 #endif
258
259     vfsswp->vsw_vfsops = &Afs_vfsops;
260     afsfstype = fstype;
261
262
263 #if     !defined(AFS_NONFSTRANS)
264     nfs_rfsdisptab_v2 = (int (*)()) modlookup("nfssrv", "rfsdisptab_v2");
265     if ( !nfs_rfsdisptab_v2 ) {
266         afs_warn("warning : rfsdisptab_v2 NOT FOUND\n");
267     }
268     if (nfs_rfsdisptab_v2) {
269         nfs_acldisptab_v2 = (int (*)()) modlookup("nfssrv", "acldisptab_v2");
270         if ( !nfs_acldisptab_v2 ) {
271             afs_warn("warning : acldisptab_v2 NOT FOUND\n");
272         }
273         else {
274             afs_xlatorinit_v2(nfs_rfsdisptab_v2, nfs_acldisptab_v2);
275         }
276     }
277     nfs_rfsdisptab_v3 = (int (*)()) modlookup("nfssrv", "rfsdisptab_v3");
278     if ( !nfs_rfsdisptab_v3 ) {
279         afs_warn("warning : rfsdisptab_v3 NOT FOUND\n");
280     }
281     if (nfs_rfsdisptab_v3) {
282         nfs_acldisptab_v3 = (int (*)()) modlookup("nfssrv", "acldisptab_v3");
283         if ( !nfs_acldisptab_v3 ) {
284             afs_warn("warning : acldisptab_v3 NOT FOUND\n");
285         }
286         else {
287             afs_xlatorinit_v3(nfs_rfsdisptab_v3, nfs_acldisptab_v3);
288         }
289     }
290
291     nfs_checkauth = (int (*)()) modlookup("nfssrv", "checkauth");
292     if ( !nfs_checkauth ) afs_warn("nfs_checkauth not initialised");
293 #endif
294     ufs_iputp = (int (*)()) modlookup("ufs", "ufs_iput");    
295     ufs_iallocp = (int (*)()) modlookup("ufs", "ufs_ialloc");    
296     ufs_iupdatp = (int (*)()) modlookup("ufs", "ufs_iupdat");
297     ufs_igetp = (int (*)()) modlookup("ufs", "ufs_iget");    
298     udp_infop = (struct streamtab *) modlookup("udp", "udpinfo");    
299     ill_g_headp = (struct ill_s *) modlookup("ip", "ill_g_head");    
300
301     if ( !ufs_iputp || !ufs_iallocp || !ufs_iupdatp ||
302          !ufs_igetp || !udp_infop || !ill_g_headp )
303         afs_warn("AFS to UFS mapping cannot be fully initialised\n");
304
305     afs_sinited = 1;
306     return 0;
307
308 }
309
310 static struct vfssw afs_vfw = {
311     "afs",
312     afsinit,
313     &Afs_vfsops,
314     0
315     };
316
317 static struct sysent afssysent = {
318     6,
319     0,
320     Afs_syscall
321     };
322
323 /* inter-module dependencies */
324 char _depends_on[] = "drv/ip drv/udp strmod/rpcmod";
325
326 /*
327  * Info/Structs to link the afs module into the kernel
328  */
329 extern struct mod_ops mod_fsops;
330 extern struct mod_ops mod_syscallops;
331
332 static struct modlfs afsmodlfs = {
333     &mod_fsops,
334     "afs filesystem",
335     &afs_vfw
336     };
337
338 static struct modlsys afsmodlsys = {
339     &mod_syscallops,
340     "afs syscall interface",
341     &afssysent
342     };
343
344 /** The two structures afssysent32 and afsmodlsys32 are being added
345   * for supporting 32 bit syscalls. In Solaris 7 there are two system
346   * tables viz. sysent ans sysent32. 32 bit applications use sysent32.
347   * Since most of our user space binaries are going to be 32 bit
348   * we need to attach to sysent32 also. Note that the entry into AFS
349   * land still happens through Afs_syscall irrespective of whether we
350   * land here from sysent or sysent32
351   */
352
353 #if defined(AFS_SUN57_64BIT_ENV)
354 extern struct mod_ops mod_syscallops32;
355
356 static struct modlsys afsmodlsys32 = {
357     &mod_syscallops32,
358     "afs syscall interface(32 bit)",
359     &afssysent
360 };
361 #endif
362
363
364 static struct modlinkage afs_modlinkage = {
365     MODREV_1,
366     (void *)&afsmodlsys,
367 #ifdef AFS_SUN57_64BIT_ENV
368     (void *)&afsmodlsys32,
369 #endif
370     (void *)&afsmodlfs,
371     NULL
372     };
373
374 /** This is the function that modload calls when loading the afs kernel
375   * extensions. The solaris modload program searches for the _init
376   * function in a module and calls it when modloading
377   */
378
379 _init()
380 {
381     char *sysn, *mod_getsysname();
382     int code;
383     extern char *sysbind;
384     extern struct bind *sb_hashtab[];
385     struct modctl *mp = 0;
386
387     if ((!(mp = mod_find_by_filename("fs", "ufs")) && 
388         !(mp = mod_find_by_filename(NULL, "/kernel/fs/ufs")) &&
389         !(mp = mod_find_by_filename(NULL, "sys/ufs"))) ||
390         (mp && !mp->mod_installed)) {
391         printf("ufs module must be loaded before loading afs; use modload /kernel/fs/ufs\n");
392         return (ENOSYS);
393     }
394 #ifndef AFS_NONFSTRANS
395 #if     defined(AFS_SUN55_ENV)
396     if ((!(mp = mod_find_by_filename("misc", "nfssrv")) &&
397          !(mp = mod_find_by_filename(NULL, NFSSRV)) &&
398          !(mp = mod_find_by_filename(NULL, NFSSRV_V9))) || 
399         (mp && !mp->mod_installed)) {
400         printf("misc/nfssrv module must be loaded before loading afs with nfs-xlator\n");
401         return (ENOSYS);
402     }
403 #else
404 #if     defined(AFS_SUN52_ENV)
405     if ((!(mp = mod_find_by_filename("fs", "nfs")) && 
406         !(mp = mod_find_by_filename(NULL, "/kernel/fs/nfs")) &&
407         !(mp = mod_find_by_filename(NULL, "sys/nfs"))) ||
408         (mp && !mp->mod_installed)) {
409         printf("fs/nfs module must be loaded before loading afs with nfs-xlator\n");
410         return (ENOSYS);
411     }
412 #endif
413 #endif
414 #endif
415     /* 
416      * Re-read the /etc/name_to_sysnum file to make sure afs isn't added after
417      * reboot.  Ideally we would like to call modctl_read_sysbinding_file() but
418      * unfortunately in Solaris 2.2 it became a local function so we have to do
419      * the read_binding_file() direct call with the appropriate text file and
420      * system call hashtable.  make_syscallname actually copies "afs" to the
421      * proper slot entry and we also actually have to properly initialize the
422      * global sysent[AFS_SYSCALL] entry!
423      */
424 #ifdef  AFS_SUN53_ENV
425 #ifndef SYSBINDFILE
426 #define SYSBINDFILE     "/etc/name_to_sysnum"
427 #endif
428     read_binding_file(SYSBINDFILE, sb_hashtab);
429 #else
430     read_binding_file(sysbind, sb_hashtab);
431 #endif
432     make_syscallname("afs", AFS_SYSCALL);
433
434     if (sysent[AFS_SYSCALL].sy_call == nosys) {
435         if ((sysn = mod_getsysname(AFS_SYSCALL)) != NULL) {
436             sysent[AFS_SYSCALL].sy_lock =
437                 (krwlock_t *) kobj_zalloc(sizeof (krwlock_t), KM_SLEEP);
438             rw_init(sysent[AFS_SYSCALL].sy_lock, "afs_syscall",
439 #ifdef AFS_SUN57_ENV
440                     RW_DEFAULT, NULL);
441 #else
442                         RW_DEFAULT, DEFAULT_WT);
443 #endif  
444         }
445     }
446
447     osi_Init();                         /* initialize global lock, etc */
448
449     code = mod_install(&afs_modlinkage);
450     return code;
451 }
452
453 _info(modp)
454     struct modinfo *modp;
455 {
456     int code;
457
458     code = mod_info(&afs_modlinkage, modp);
459     return code;
460 }
461
462 _fini()
463 {
464     int code;
465
466     if (afs_sinited)
467         return (EBUSY);
468     code = mod_remove(&afs_modlinkage);
469     return code;
470 }