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