solaris-fs-agnostic-cache-20081130
[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
14     ("$Header$");
15
16 #include "afs/sysincludes.h"    /* Standard vendor system headers */
17 #include "afsincludes.h"        /* Afs-based standard headers */
18 #include "afs/afs_stats.h"      /* afs statistics */
19 #include "afs/osi_inode.h"
20
21
22 int afs_osicred_initialized = 0;
23 struct AFS_UCRED afs_osi_cred;
24 afs_lock_t afs_xosi;            /* lock is for tvattr */
25 extern struct osi_dev cacheDev;
26 extern struct vfs *afs_cacheVfsp;
27
28
29 #ifdef AFS_HAVE_VXFS
30
31 /* Support for UFS and VXFS caches. The assumption here is that the size of
32  * a cache file also does not exceed 32 bits. 
33  */
34
35 /* Initialized in osi_InitCacheFSType(). Used to determine inode type. */
36 int afs_CacheFSType = -1;
37
38 /* pointer to VXFS routine to access vnodes by inode number */
39 int (*vxfs_vx_vp_byino) ();
40
41 /* Initialize the cache operations. Called while initializing cache files. */
42 void
43 afs_InitDualFSCacheOps(struct vnode *vp)
44 {
45     int code;
46     static int inited = 0;
47     struct vfs *vfsp;
48 #ifdef AFS_SUN56_ENV
49     struct statvfs64 vfst;
50 #else /* AFS_SUN56_ENV */
51     struct statvfs vfst;
52 #endif /* AFS_SUN56_ENV */
53
54     if (inited)
55         return;
56     inited = 1;
57
58     if (vp == NULL)
59         return;
60
61     vfsp = vp->v_vfsp;
62     if (vfsp == NULL)
63         osi_Panic("afs_InitDualFSCacheOps: vp->v_vfsp is NULL");
64     code = VFS_STATVFS(vfsp, &vfst);
65     if (code)
66         osi_Panic("afs_InitDualFSCacheOps: statvfs failed");
67
68     if (strcmp(vfst.f_basetype, "vxfs") == 0) {
69         vxfs_vx_vp_byino = (int (*)())modlookup("vxfs", "vx_vp_byino");
70         if (vxfs_vx_vp_byino == NULL)
71             osi_Panic
72                 ("afs_InitDualFSCacheOps: modlookup(vx_vp_byino) failed");
73
74         afs_CacheFSType = AFS_SUN_VXFS_CACHE;
75         return;
76     }
77
78     afs_CacheFSType = AFS_SUN_UFS_CACHE;
79     return;
80 }
81
82 ino_t
83 VnodeToIno(vnode_t * vp)
84 {
85     int code;
86     struct vattr vattr;
87
88     vattr.va_mask = AT_FSID | AT_NODEID;        /* quick return using this mask. */
89 #ifdef AFS_SUN511_ENV
90     code = VOP_GETATTR(vp, &vattr, 0, &afs_osi_cred, NULL);
91 #else
92     code = VOP_GETATTR(vp, &vattr, 0, &afs_osi_cred);
93 #endif
94     if (code) {
95         osi_Panic("VnodeToIno");
96     }
97     return vattr.va_nodeid;
98 }
99
100 dev_t
101 VnodeToDev(vnode_t * vp)
102 {
103     int code;
104     struct vattr vattr;
105
106     vattr.va_mask = AT_FSID | AT_NODEID;        /* quick return using this mask. */
107     AFS_GUNLOCK();
108 #ifdef AFS_SUN511_ENV
109     code = VOP_GETATTR(vp, &vattr, 0, &afs_osi_cred, NULL);
110 #else
111     code = VOP_GETATTR(vp, &vattr, 0, &afs_osi_cred);
112 #endif
113     AFS_GLOCK();
114     if (code) {
115         osi_Panic("VnodeToDev");
116     }
117     return (dev_t) vattr.va_fsid;
118 }
119
120 afs_int32
121 VnodeToSize(vnode_t * vp)
122 {
123     int code;
124     struct vattr vattr;
125
126     /*
127      * We lock xosi in osi_Stat, so we probably should
128      * lock it here too - RWH.
129      */
130     MObtainWriteLock(&afs_xosi, 578);
131     vattr.va_mask = AT_SIZE;
132     AFS_GUNLOCK();
133 #ifdef AFS_SUN511_ENV
134     code = VOP_GETATTR(vp, &vattr, 0, &afs_osi_cred, NULL);
135 #else
136     code = VOP_GETATTR(vp, &vattr, 0, &afs_osi_cred);
137 #endif
138     AFS_GLOCK();
139     if (code) {
140         osi_Panic("VnodeToSize");
141     }
142     MReleaseWriteLock(&afs_xosi);
143     return (afs_int32) (vattr.va_size);
144 }
145
146 void *
147 osi_VxfsOpen(afs_int32 ainode)
148 {
149     struct vnode *vp;
150     register struct osi_file *afile = NULL;
151     afs_int32 code = 0;
152     int dummy;
153     afile = (struct osi_file *)osi_AllocSmallSpace(sizeof(struct osi_file));
154     AFS_GUNLOCK();
155     code = (*vxfs_vx_vp_byino) (afs_cacheVfsp, &vp, (unsigned int)ainode);
156     AFS_GLOCK();
157     if (code) {
158         osi_FreeSmallSpace(afile);
159         osi_Panic("VxfsOpen: vx_vp_byino failed");
160     }
161     afile->vnode = vp;
162     afile->size = VnodeToSize(afile->vnode);
163     afile->offset = 0;
164     afile->proc = (int (*)())0;
165     afile->inum = ainode;       /* for hint validity checking */
166     return (void *)afile;
167 }
168 #endif /* AFS_HAVE_VXFS */
169
170 #if defined(AFS_SUN57_64BIT_ENV)
171 void *
172 osi_UfsOpen(ino_t ainode)
173 #else
174 void *
175 osi_UfsOpen(afs_int32 ainode)
176 #endif
177 {
178 #ifdef AFS_CACHE_VNODE_PATH
179     struct vnode *vp;
180 #else
181     struct inode *ip;
182 #endif
183     register struct osi_file *afile = NULL;
184     afs_int32 code = 0;
185 #ifdef AFS_CACHE_VNODE_PATH
186     int dummy;
187     char fname[1024];
188     char namebuf[1024];
189     struct pathname lookpn;
190 #endif
191     struct osi_stat tstat;
192     afile = (struct osi_file *)osi_AllocSmallSpace(sizeof(struct osi_file));
193     AFS_GUNLOCK();
194
195 /*
196  * AFS_CACHE_VNODE_PATH can be used with any file system, including ZFS or tmpfs.
197  * The ainode is not an inode number but a signed index used to generate file names. 
198  */
199 #ifdef AFS_CACHE_VNODE_PATH
200         switch (ainode) {
201         case AFS_CACHE_CELLS_INODE:
202             snprintf(fname, 1024, "%s/%s", afs_cachebasedir, "CellItems");
203             break;
204         case AFS_CACHE_ITEMS_INODE:
205             snprintf(fname, 1024, "%s/%s", afs_cachebasedir, "CacheItems");
206             break;
207         case AFS_CACHE_VOLUME_INODE:
208             snprintf(fname, 1024, "%s/%s", afs_cachebasedir, "VolumeItems");
209             break;
210         default:
211                 dummy = ainode / afs_numfilesperdir;
212                 snprintf(fname, 1024, "%s/D%d/V%d", afs_cachebasedir, dummy, ainode);
213     }
214                 
215         /* Can not use vn_open or lookupname, they use user's CRED() 
216      * We need to run as root So must use low level lookuppnvp 
217      * assume fname starts with /
218          */
219
220         code = pn_get_buf(fname, AFS_UIOSYS, &lookpn, namebuf, sizeof(namebuf));
221     if (code != 0) 
222         osi_Panic("UfsOpen: pn_get_buf failed %ld %s %ld", code, fname, ainode);
223  
224         VN_HOLD(rootdir); /* released in loopuppnvp */
225         code = lookuppnvp(&lookpn, NULL, FOLLOW, NULL, &vp, 
226            rootdir, rootdir, &afs_osi_cred); 
227     if (code != 0)  
228         osi_Panic("UfsOpen: lookuppnvp failed %ld %s %ld", code, fname, ainode);
229         
230 #ifdef AFS_SUN511_ENV
231     code = VOP_OPEN(&vp, FREAD|FWRITE, &afs_osi_cred, NULL);
232 #else
233     code = VOP_OPEN(&vp, FREAD|FWRITE, &afs_osi_cred);
234 #endif
235
236     if (code != 0)
237         osi_Panic("UfsOpen: VOP_OPEN failed %ld %s %ld", code, fname, ainode);
238
239 #else
240     code =
241         igetinode(afs_cacheVfsp, (dev_t) cacheDev.dev, (ino_t) ainode, &ip,
242                   CRED(), &dummy);
243 #endif
244     AFS_GLOCK();
245     if (code) {
246         osi_FreeSmallSpace(afile);
247         osi_Panic("UfsOpen: igetinode failed %ld %s %ld", code, fname, ainode);
248     }
249 #ifdef AFS_CACHE_VNODE_PATH
250         afile->vnode = vp;
251         code = afs_osi_Stat(afile, &tstat);
252         afile->size = tstat.size;
253 #else
254     afile->vnode = ITOV(ip);
255     afile->size = VTOI(afile->vnode)->i_size;
256 #endif
257     afile->offset = 0;
258     afile->proc = (int (*)())0;
259     afile->inum = ainode;       /* for hint validity checking */
260     return (void *)afile;
261 }
262
263 /**
264   * In Solaris 7 we use 64 bit inode numbers
265   */
266 #if defined(AFS_SUN57_64BIT_ENV)
267 void *
268 osi_UFSOpen(ino_t ainode)
269 #else
270 void *
271 osi_UFSOpen(afs_int32 ainode)
272 #endif
273 {
274     extern int cacheDiskType;
275     AFS_STATCNT(osi_UFSOpen);
276     if (cacheDiskType != AFS_FCACHE_TYPE_UFS) {
277         osi_Panic("UFSOpen called for non-UFS cache\n");
278     }
279     if (!afs_osicred_initialized) {
280         /* valid for alpha_osf, SunOS, Ultrix */
281         memset((char *)&afs_osi_cred, 0, sizeof(struct AFS_UCRED));
282         crhold(&afs_osi_cred);  /* don't let it evaporate, since it is static */
283         afs_osicred_initialized = 1;
284     }
285 #ifdef AFS_HAVE_VXFS
286     if (afs_CacheFSType == AFS_SUN_VXFS_CACHE)
287         return osi_VxfsOpen(ainode);
288 #endif
289     return osi_UfsOpen(ainode);
290 }
291
292 int
293 afs_osi_Stat(register struct osi_file *afile, register struct osi_stat *astat)
294 {
295     register afs_int32 code;
296     struct vattr tvattr;
297     AFS_STATCNT(osi_Stat);
298     MObtainWriteLock(&afs_xosi, 320);
299     /* Ufs doesn't seem to care about the flags so we pass 0 for now */
300     tvattr.va_mask = AT_ALL;
301     AFS_GUNLOCK();
302 #ifdef AFS_SUN511_ENV 
303     code = VOP_GETATTR(afile->vnode, &tvattr, 0, &afs_osi_cred, NULL);
304 #else
305     code = VOP_GETATTR(afile->vnode, &tvattr, 0, &afs_osi_cred);
306 #endif
307     AFS_GLOCK();
308     if (code == 0) {
309         astat->size = tvattr.va_size;
310         astat->mtime = tvattr.va_mtime.tv_sec;
311         astat->atime = tvattr.va_atime.tv_sec;
312     }
313     MReleaseWriteLock(&afs_xosi);
314     return code;
315 }
316
317 int
318 osi_UFSClose(register struct osi_file *afile)
319 {
320     AFS_STATCNT(osi_Close);
321     if (afile->vnode) {
322         AFS_RELE(afile->vnode);
323     }
324
325     osi_FreeSmallSpace(afile);
326     return 0;
327 }
328
329 int
330 osi_UFSTruncate(register struct osi_file *afile, afs_int32 asize)
331 {
332     struct AFS_UCRED *oldCred;
333     struct vattr tvattr;
334     register afs_int32 code;
335     struct osi_stat tstat;
336     AFS_STATCNT(osi_Truncate);
337
338     /* This routine only shrinks files, and most systems
339      * have very slow truncates, even when the file is already
340      * small enough.  Check now and save some time.
341      */
342     code = afs_osi_Stat(afile, &tstat);
343     if (code || tstat.size <= asize)
344         return code;
345     MObtainWriteLock(&afs_xosi, 321);
346     tvattr.va_mask = AT_SIZE;
347     tvattr.va_size = asize;
348     /*
349      * The only time a flag is used (ATTR_UTIME) is when we're changing the time 
350      */
351     AFS_GUNLOCK();
352 #ifdef AFS_SUN510_ENV
353     {
354         caller_context_t ct;
355
356         code = VOP_SETATTR(afile->vnode, &tvattr, 0, &afs_osi_cred, &ct);
357     }
358 #else
359     code = VOP_SETATTR(afile->vnode, &tvattr, 0, &afs_osi_cred);
360 #endif
361     AFS_GLOCK();
362     MReleaseWriteLock(&afs_xosi);
363     return code;
364 }
365
366 void
367 osi_DisableAtimes(struct vnode *avp)
368 {
369     if (afs_CacheFSType == AFS_SUN_UFS_CACHE) {
370 #ifndef AFS_CACHE_VNODE_PATH 
371         struct inode *ip = VTOI(avp);
372         rw_enter(&ip->i_contents, RW_READER);
373         mutex_enter(&ip->i_tlock);
374         ip->i_flag &= ~IACC;
375         mutex_exit(&ip->i_tlock);
376         rw_exit(&ip->i_contents);
377 #endif
378     }
379 }
380
381
382 /* Generic read interface */
383 int
384 afs_osi_Read(register struct osi_file *afile, int offset, void *aptr,
385              afs_int32 asize)
386 {
387     struct AFS_UCRED *oldCred;
388 #if defined(AFS_SUN57_ENV)
389     ssize_t resid;
390 #else
391     int resid;
392 #endif
393     register afs_int32 code;
394     register afs_int32 cnt1 = 0;
395     AFS_STATCNT(osi_Read);
396
397     /**
398       * If the osi_file passed in is NULL, panic only if AFS is not shutting
399       * down. No point in crashing when we are already shutting down
400       */
401     if (!afile) {
402         if (!afs_shuttingdown)
403             osi_Panic("osi_Read called with null param");
404         else
405             return EIO;
406     }
407
408     if (offset != -1)
409         afile->offset = offset;
410     AFS_GUNLOCK();
411     code =
412         gop_rdwr(UIO_READ, afile->vnode, (caddr_t) aptr, asize, afile->offset,
413                  AFS_UIOSYS, 0, 0, &afs_osi_cred, &resid);
414     AFS_GLOCK();
415     if (code == 0) {
416         code = asize - resid;
417         afile->offset += code;
418         osi_DisableAtimes(afile->vnode);
419     } else {
420         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, resid,
421                    ICL_TYPE_INT32, code);
422         code = -1;
423     }
424     return code;
425 }
426
427 /* Generic write interface */
428 int
429 afs_osi_Write(register struct osi_file *afile, afs_int32 offset, void *aptr,
430               afs_int32 asize)
431 {
432     struct AFS_UCRED *oldCred;
433 #if defined(AFS_SUN57_ENV)
434     ssize_t resid;
435 #else
436     int resid;
437 #endif
438     register afs_int32 code;
439     AFS_STATCNT(osi_Write);
440     if (!afile)
441         osi_Panic("afs_osi_Write called with null param");
442     if (offset != -1)
443         afile->offset = offset;
444     AFS_GUNLOCK();
445     code =
446         gop_rdwr(UIO_WRITE, afile->vnode, (caddr_t) aptr, asize,
447                  afile->offset, AFS_UIOSYS, 0, RLIM64_INFINITY, &afs_osi_cred,
448                  &resid);
449     AFS_GLOCK();
450     if (code == 0) {
451         code = asize - resid;
452         afile->offset += code;
453     } else {
454         code = -1;
455     }
456     if (afile->proc) {
457         (*afile->proc) (afile, code);
458     }
459     return code;
460 }
461
462
463 /*  This work should be handled by physstrat in ca/machdep.c.
464     This routine written from the RT NFS port strategy routine.
465     It has been generalized a bit, but should still be pretty clear. */
466 int
467 afs_osi_MapStrategy(int (*aproc) (), register struct buf *bp)
468 {
469     afs_int32 returnCode;
470
471     AFS_STATCNT(osi_MapStrategy);
472     returnCode = (*aproc) (bp);
473
474     return returnCode;
475 }
476
477
478
479 void
480 shutdown_osifile(void)
481 {
482     AFS_STATCNT(shutdown_osifile);
483     if (afs_cold_shutdown) {
484         afs_osicred_initialized = 0;
485     }
486 }