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