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