068c1a70fdef0893a89893558c0f9d388c055ebf
[openafs.git] / src / afs / SOLARIS / osi_file.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 #include <afsconfig.h>
11 #include "../afs/param.h"
12
13 RCSID("$Header$");
14
15 #include "../afs/sysincludes.h" /* Standard vendor system headers */
16 #include "../afs/afsincludes.h" /* Afs-based standard headers */
17 #include "../afs/afs_stats.h"  /* afs statistics */
18 #include "../afs/osi_inode.h"
19
20
21 int afs_osicred_initialized=0;
22 struct  AFS_UCRED afs_osi_cred;
23 afs_lock_t afs_xosi;            /* lock is for tvattr */
24 extern struct osi_dev cacheDev;
25 extern struct vfs *afs_cacheVfsp;
26
27
28 #ifdef AFS_HAVE_VXFS
29
30 /* Support for UFS and VXFS caches. The assumption here is that the size of
31  * a cache file also does not exceed 32 bits. 
32  */
33
34 /* Initialized in osi_InitCacheFSType(). Used to determine inode type. */
35 int afs_CacheFSType = -1;
36
37 /* pointer to VXFS routine to access vnodes by inode number */
38 int (*vxfs_vx_vp_byino)();
39
40 /* Initialize the cache operations. Called while initializing cache files. */
41 void afs_InitDualFSCacheOps(struct vnode *vp)
42 {
43     int code;
44     static int inited = 0;
45     struct vfs *vfsp;
46 #ifdef AFS_SUN56_ENV
47     struct statvfs64 vfst;
48 #else  /* AFS_SUN56_ENV */
49     struct statvfs vfst;
50 #endif /* AFS_SUN56_ENV */
51
52     if (inited)
53         return;
54     inited = 1;
55
56     if (vp == NULL)
57         return;
58
59     vfsp = vp->v_vfsp;
60     if (vfsp == NULL)
61         osi_Panic("afs_InitDualFSCacheOps: vp->v_vfsp is NULL");
62     code = VFS_STATVFS(vfsp, &vfst);
63     if (code)
64         osi_Panic("afs_InitDualFSCacheOps: statvfs failed");
65
66     if (strcmp(vfst.f_basetype, "vxfs") == 0) {
67         vxfs_vx_vp_byino = (int (*)())modlookup("vxfs", "vx_vp_byino");
68         if (vxfs_vx_vp_byino == NULL)
69             osi_Panic("afs_InitDualFSCacheOps: modlookup(vx_vp_byino) failed");
70
71         afs_CacheFSType = AFS_SUN_VXFS_CACHE;
72         return;
73     }
74
75     afs_CacheFSType = AFS_SUN_UFS_CACHE;
76     return;
77 }
78
79 ino_t VnodeToIno(vnode_t *vp)
80 {
81     int code;
82     struct vattr vattr;
83
84     vattr.va_mask = AT_FSID|AT_NODEID; /* quick return using this mask. */
85     code = VOP_GETATTR(vp, &vattr, 0, &afs_osi_cred);
86     if (code) {
87         osi_Panic("VnodeToIno");
88     }
89     return vattr.va_nodeid;
90 }
91
92 dev_t VnodeToDev(vnode_t *vp)
93 {
94     int code;
95     struct vattr vattr;
96
97     vattr.va_mask = AT_FSID|AT_NODEID; /* quick return using this mask. */
98     AFS_GUNLOCK();
99     code = VOP_GETATTR(vp, &vattr, 0, &afs_osi_cred);
100     AFS_GLOCK();
101     if (code) {
102         osi_Panic("VnodeToDev");
103     }
104     return (dev_t)vattr.va_fsid;
105 }
106
107 afs_int32 VnodeToSize(vnode_t *vp)
108 {
109     int code;
110     struct vattr vattr;
111
112     /*
113      * We lock xosi in osi_Stat, so we probably should
114      * lock it here too - RWH.
115      */ 
116     MObtainWriteLock(&afs_xosi,578);
117     vattr.va_mask = AT_SIZE;
118     AFS_GUNLOCK();
119     code = VOP_GETATTR(vp, &vattr, 0, &afs_osi_cred);
120     AFS_GLOCK();
121     if (code) {
122         osi_Panic("VnodeToSize");
123     }
124     MReleaseWriteLock(&afs_xosi);
125     return (afs_int32)(vattr.va_size);
126 }
127
128 void *osi_VxfsOpen(ainode)
129     afs_int32 ainode;
130 {
131     struct vnode *vp;
132     register struct osi_file *afile = NULL;
133     afs_int32 code = 0;
134     int dummy;
135     afile = (struct osi_file *) osi_AllocSmallSpace(sizeof(struct osi_file));
136     AFS_GUNLOCK();
137     code = (*vxfs_vx_vp_byino)(afs_cacheVfsp, &vp, (unsigned int)ainode);
138     AFS_GLOCK();
139     if (code) {
140         osi_FreeSmallSpace(afile);
141         osi_Panic("VxfsOpen: vx_vp_byino failed");
142     }
143     afile->vnode = vp;
144     afile->size = VnodeToSize(afile->vnode);
145     afile->offset = 0;
146     afile->proc = (int (*)()) 0;
147     afile->inum = ainode;        /* for hint validity checking */
148     return (void *)afile;
149 }
150 #endif /* AFS_HAVE_VXFS */
151
152 void *osi_UfsOpen(ainode)
153     afs_int32 ainode;
154 {
155     struct inode *ip;
156     register struct osi_file *afile = NULL;
157     afs_int32 code = 0;
158     int dummy;
159     afile = (struct osi_file *) osi_AllocSmallSpace(sizeof(struct osi_file));
160     AFS_GUNLOCK();
161     code = igetinode(afs_cacheVfsp, (dev_t) cacheDev.dev, (ino_t)ainode, &ip, CRED(),&dummy);
162     AFS_GLOCK();
163     if (code) {
164         osi_FreeSmallSpace(afile);
165         osi_Panic("UfsOpen: igetinode failed");
166     }
167     afile->vnode = ITOV(ip);
168     afile->size = VTOI(afile->vnode)->i_size;
169     afile->offset = 0;
170     afile->proc = (int (*)()) 0;
171     afile->inum = ainode;        /* for hint validity checking */
172     return (void *)afile;
173 }
174
175 /**
176   * In Solaris 7 we use 64 bit inode numbers
177   */
178 #if defined(AFS_SUN57_64BIT_ENV)
179 void *osi_UFSOpen(ino_t ainode)
180 #else
181 void *osi_UFSOpen(ainode)
182     afs_int32 ainode;
183 #endif
184 {
185     extern int cacheDiskType;
186     AFS_STATCNT(osi_UFSOpen);
187     if(cacheDiskType != AFS_FCACHE_TYPE_UFS) {
188         osi_Panic("UFSOpen called for non-UFS cache\n");
189     }
190     if (!afs_osicred_initialized) {
191         /* valid for alpha_osf, SunOS, Ultrix */
192         memset((char *)&afs_osi_cred, 0, sizeof(struct AFS_UCRED));
193         crhold(&afs_osi_cred);  /* don't let it evaporate, since it is static */
194         afs_osicred_initialized = 1;
195     }
196 #ifdef AFS_HAVE_VXFS
197     if (afs_CacheFSType == AFS_SUN_VXFS_CACHE)
198         return osi_VxfsOpen(ainode);
199 #endif
200     return osi_UfsOpen(ainode);
201 }
202
203 afs_osi_Stat(afile, astat)
204     register struct osi_file *afile;
205     register struct osi_stat *astat; {
206     register afs_int32 code;
207     struct vattr tvattr;
208     AFS_STATCNT(osi_Stat);
209     MObtainWriteLock(&afs_xosi,320);
210     /* Ufs doesn't seem to care about the flags so we pass 0 for now */
211     tvattr.va_mask = AT_ALL;
212     AFS_GUNLOCK();
213     code = VOP_GETATTR(afile->vnode, &tvattr, 0, &afs_osi_cred);
214     AFS_GLOCK();
215     if (code == 0) {
216         astat->size = tvattr.va_size;
217         astat->blksize = tvattr.va_blksize;
218         astat->mtime = tvattr.va_mtime.tv_sec;
219         astat->atime = tvattr.va_atime.tv_sec;
220     }
221     MReleaseWriteLock(&afs_xosi);
222     return code;
223 }
224
225 osi_UFSClose(afile)
226      register struct osi_file *afile;
227   {
228       AFS_STATCNT(osi_Close);
229       if(afile->vnode) {
230         AFS_RELE(afile->vnode);
231       }
232       
233       osi_FreeSmallSpace(afile);
234       return 0;
235   }
236
237 osi_UFSTruncate(afile, asize)
238     register struct osi_file *afile;
239     afs_int32 asize; {
240     struct AFS_UCRED *oldCred;
241     struct vattr tvattr;
242     register afs_int32 code;
243     struct osi_stat tstat;
244     AFS_STATCNT(osi_Truncate);
245
246     /* This routine only shrinks files, and most systems
247      * have very slow truncates, even when the file is already
248      * small enough.  Check now and save some time.
249      */
250     code = afs_osi_Stat(afile, &tstat);
251     if (code || tstat.size <= asize) return code;
252     MObtainWriteLock(&afs_xosi,321);    
253     tvattr.va_mask = AT_SIZE;
254     tvattr.va_size = asize;
255     /*
256      * The only time a flag is used (ATTR_UTIME) is when we're changing the time 
257      */
258     AFS_GUNLOCK();
259     code = VOP_SETATTR(afile->vnode, &tvattr, 0, &afs_osi_cred);
260     AFS_GLOCK();
261     MReleaseWriteLock(&afs_xosi);
262     return code;
263 }
264
265 void osi_DisableAtimes(avp)
266 struct vnode *avp;
267 {
268    if (afs_CacheFSType == AFS_SUN_UFS_CACHE) {
269        struct inode *ip = VTOI(avp);
270        rw_enter(&ip->i_contents, RW_READER);
271        mutex_enter(&ip->i_tlock);
272        ip->i_flag &= ~IACC;
273        mutex_exit(&ip->i_tlock);
274        rw_exit(&ip->i_contents);
275    }
276 }
277
278
279 /* Generic read interface */
280 afs_osi_Read(afile, offset, aptr, asize)
281     register struct osi_file *afile;
282     int offset;
283     char *aptr;
284     afs_int32 asize; {
285     struct AFS_UCRED *oldCred;
286 #if defined(AFS_SUN57_ENV)
287     ssize_t resid;
288 #else
289     int resid;
290 #endif
291     register afs_int32 code;
292     register afs_int32 cnt1=0;
293     AFS_STATCNT(osi_Read);
294
295     /**
296       * If the osi_file passed in is NULL, panic only if AFS is not shutting
297       * down. No point in crashing when we are already shutting down
298       */
299     if ( !afile ) {
300         if ( !afs_shuttingdown )
301            osi_Panic("osi_Read called with null param");
302         else
303             return EIO;
304     }
305
306     if (offset != -1) afile->offset = offset;
307     AFS_GUNLOCK();
308     code = gop_rdwr(UIO_READ, afile->vnode, (caddr_t) aptr, asize, afile->offset,
309                   AFS_UIOSYS, 0, 0, &afs_osi_cred, &resid);
310     AFS_GLOCK();
311     if (code == 0) {
312         code = asize - resid;
313         afile->offset += code;
314         osi_DisableAtimes(afile->vnode);
315     }
316     else {
317         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, resid,
318                  ICL_TYPE_INT32, code);
319         code = -1;
320     }
321     return code;
322 }
323
324 /* Generic write interface */
325 afs_osi_Write(afile, offset, aptr, asize)
326     register struct osi_file *afile;
327     char *aptr;
328     afs_int32 offset;
329     afs_int32 asize; {
330     struct AFS_UCRED *oldCred;
331 #if defined(AFS_SUN57_ENV)
332     ssize_t resid;
333 #else
334    int resid;
335 #endif
336     register afs_int32 code;
337     AFS_STATCNT(osi_Write);
338     if ( !afile )
339         osi_Panic("afs_osi_Write called with null param");
340     if (offset != -1) afile->offset = offset;
341     AFS_GUNLOCK();
342     code = gop_rdwr(UIO_WRITE, afile->vnode, (caddr_t) aptr, asize, afile->offset,
343                   AFS_UIOSYS, 0,  (u.u_rlimit[RLIMIT_FSIZE].rlim_cur), &afs_osi_cred, &resid);
344     AFS_GLOCK();
345     if (code == 0) {
346         code = asize - resid;
347         afile->offset += code;
348     }
349     else {
350         code = -1;
351     }
352     if (afile->proc) {
353         (*afile->proc)(afile, code);
354     }
355     return code;
356 }
357
358
359 /*  This work should be handled by physstrat in ca/machdep.c.
360     This routine written from the RT NFS port strategy routine.
361     It has been generalized a bit, but should still be pretty clear. */
362 int afs_osi_MapStrategy(aproc, bp)
363         int (*aproc)();
364         register struct buf *bp;
365 {
366     afs_int32 returnCode;
367
368     AFS_STATCNT(osi_MapStrategy);
369     returnCode = (*aproc) (bp);
370
371     return returnCode;
372 }
373
374
375
376 void
377 shutdown_osifile()
378 {
379   extern int afs_cold_shutdown;
380
381   AFS_STATCNT(shutdown_osifile);
382   if (afs_cold_shutdown) {
383     afs_osicred_initialized = 0;
384   }
385 }
386