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