macos: make the OpenAFS client aware of APFS
[openafs.git] / src / afs / DARWIN / 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_ucred_t afs_osi_cred;
22 afs_lock_t afs_xosi;            /* lock is for tvattr */
23 extern struct osi_dev cacheDev;
24 extern struct mount *afs_cacheVfsp;
25 int afs_CacheFSType = -1;
26
27 /* Initialize the cache operations. Called while initializing cache files. */
28 void
29 afs_InitDualFSCacheOps(struct vnode *vp)
30 {
31     int code;
32     static int inited = 0;
33 #ifdef AFS_DARWIN80_ENV
34     char *buffer = (char*)_MALLOC(MFSNAMELEN, M_TEMP, M_WAITOK);
35 #endif
36
37     if (inited)
38         return;
39     inited = 1;
40
41     if (vp == NULL)
42         return;
43 #ifdef AFS_DARWIN80_ENV
44     vfs_name(vnode_mount(vp), buffer);
45     if (strncmp("hfs", buffer, 3) == 0)
46 #else
47     if (strncmp("hfs", vp->v_mount->mnt_vfc->vfc_name, 3) == 0)
48 #endif
49         afs_CacheFSType = AFS_APPL_HFS_CACHE;
50 #ifdef AFS_DARWIN80_ENV
51     else if (strncmp("ufs", buffer, 3) == 0)
52 #else
53     else if (strncmp("ufs", vp->v_mount->mnt_vfc->vfc_name, 3) == 0)
54 #endif
55         afs_CacheFSType = AFS_APPL_UFS_CACHE;
56 #ifdef AFS_DARWIN80_ENV
57     else if (strncmp("apfs", buffer, 4) == 0)
58         afs_CacheFSType = AFS_APPL_APFS_CACHE;
59 #endif
60     else
61         osi_Panic("Unknown cache vnode type\n");
62 #ifdef AFS_DARWIN80_ENV
63     _FREE(buffer, M_TEMP);
64 #endif
65 }
66
67 ino_t
68 VnodeToIno(vnode_t avp)
69 {
70     unsigned long ret;
71
72 #ifndef AFS_DARWIN80_ENV
73     if (afs_CacheFSType == AFS_APPL_UFS_CACHE) {
74         struct inode *ip = VTOI(avp);
75         ret = ip->i_number;
76     } else if (afs_CacheFSType == AFS_APPL_HFS_CACHE) {
77 #endif
78 #if defined(AFS_DARWIN80_ENV) 
79         struct vattr va;
80         VATTR_INIT(&va);
81         VATTR_WANTED(&va, va_fileid);
82         if (vnode_getattr(avp, &va, afs_osi_ctxtp))
83             osi_Panic("VOP_GETATTR failed in VnodeToIno\n");
84         if (!VATTR_ALL_SUPPORTED(&va))
85             osi_Panic("VOP_GETATTR unsupported fileid in VnodeToIno\n");
86         ret = va.va_fileid;
87 #elif !defined(VTOH)
88         struct vattr va;
89         if (VOP_GETATTR(avp, &va, &afs_osi_cred, current_proc()))
90             osi_Panic("VOP_GETATTR failed in VnodeToIno\n");
91         ret = va.va_fileid;
92 #else
93         struct hfsnode *hp = VTOH(avp);
94         ret = H_FILEID(hp);
95 #endif
96 #ifndef AFS_DARWIN80_ENV
97     } else
98         osi_Panic("VnodeToIno called before cacheops initialized\n");
99 #endif
100     return ret;
101 }
102
103
104 dev_t
105 VnodeToDev(vnode_t avp)
106 {
107 #ifndef AFS_DARWIN80_ENV
108     if (afs_CacheFSType == AFS_APPL_UFS_CACHE) {
109         struct inode *ip = VTOI(avp);
110         return ip->i_dev;
111     } else if (afs_CacheFSType == AFS_APPL_HFS_CACHE) {
112 #endif
113 #if defined(AFS_DARWIN80_ENV) 
114         struct vattr va;
115         VATTR_INIT(&va);
116         VATTR_WANTED(&va, va_fsid);
117         if (vnode_getattr(avp, &va, afs_osi_ctxtp))
118             osi_Panic("VOP_GETATTR failed in VnodeToDev\n");
119         if (!VATTR_ALL_SUPPORTED(&va))
120             osi_Panic("VOP_GETATTR unsupported fsid in VnodeToIno\n");
121         return va.va_fsid;      /* XXX they say it's the dev.... */
122 #elif !defined(VTOH)
123         struct vattr va;
124         if (VOP_GETATTR(avp, &va, &afs_osi_cred, current_proc()))
125             osi_Panic("VOP_GETATTR failed in VnodeToDev\n");
126         return va.va_fsid;      /* XXX they say it's the dev.... */
127 #else
128         struct hfsnode *hp = VTOH(avp);
129         return H_DEV(hp);
130 #endif
131 #ifndef AFS_DARWIN80_ENV
132     } else
133         osi_Panic("VnodeToDev called before cacheops initialized\n");
134 #endif
135 }
136
137 void *
138 osi_UFSOpen(afs_dcache_id_t *ainode)
139 {
140     struct vnode *vp;
141     struct vattr va;
142     struct osi_file *afile = NULL;
143     extern int cacheDiskType;
144     afs_int32 code = 0;
145     int dummy;
146     char fname[1024];
147     struct osi_stat tstat;
148
149     AFS_STATCNT(osi_UFSOpen);
150     if (cacheDiskType != AFS_FCACHE_TYPE_UFS) {
151         osi_Panic("UFSOpen called for non-UFS cache\n");
152     }
153     if (!afs_osicred_initialized) {
154         /* valid for alpha_osf, SunOS, Ultrix */
155         memset(&afs_osi_cred, 0, sizeof(afs_ucred_t));
156         afs_osi_cred.cr_ref++;
157 #ifndef AFS_DARWIN110_ENV
158         afs_osi_cred.cr_ngroups = 1;
159 #endif
160         afs_osicred_initialized = 1;
161     }
162     afile = osi_AllocSmallSpace(sizeof(struct osi_file));
163     AFS_GUNLOCK();
164 #ifdef AFS_CACHE_VNODE_PATH
165     if (!ainode->ufs) {
166         osi_Panic("No cache inode\n");
167     }
168
169     code = vnode_open(ainode->ufs, O_RDWR, 0, 0, &vp, afs_osi_ctxtp);
170 #else
171 #ifndef AFS_DARWIN80_ENV
172     if (afs_CacheFSType == AFS_APPL_HFS_CACHE)
173         code = igetinode(afs_cacheVfsp, (dev_t) cacheDev.dev, &ainode->ufs, &vp, &va, &dummy);  /* XXX hfs is broken */
174     else if (afs_CacheFSType == AFS_APPL_UFS_CACHE)
175 #endif
176         code =
177             igetinode(afs_cacheVfsp, (dev_t) cacheDev.dev, (ino_t) ainode->ufs,
178                       &vp, &va, &dummy);
179 #ifndef AFS_DARWIN80_ENV
180     else
181         panic("osi_UFSOpen called before cacheops initialized\n");
182 #endif
183 #endif
184     AFS_GLOCK();
185     if (code) {
186         osi_FreeSmallSpace(afile);
187         osi_Panic("UFSOpen: igetinode failed");
188     }
189     afile->vnode = vp;
190     afile->offset = 0;
191     afile->proc = (int (*)())0;
192 #ifndef AFS_CACHE_VNODE_PATH
193     afile->size = va.va_size;
194 #else
195     code = afs_osi_Stat(afile, &tstat);
196     afile->size = tstat.size;
197 #endif
198     return (void *)afile;
199 }
200
201 int
202 afs_osi_Stat(struct osi_file *afile, struct osi_stat *astat)
203 {
204     afs_int32 code;
205     struct vattr tvattr;
206     AFS_STATCNT(osi_Stat);
207     ObtainWriteLock(&afs_xosi, 320);
208     AFS_GUNLOCK();
209 #ifdef AFS_DARWIN80_ENV
210     VATTR_INIT(&tvattr);
211     VATTR_WANTED(&tvattr, va_size);
212     VATTR_WANTED(&tvattr, va_blocksize);
213     VATTR_WANTED(&tvattr, va_mtime);
214     VATTR_WANTED(&tvattr, va_atime);
215     code = vnode_getattr(afile->vnode, &tvattr, afs_osi_ctxtp);
216     if (code == 0 && !VATTR_ALL_SUPPORTED(&tvattr))
217        code = EINVAL;
218 #else
219     code = VOP_GETATTR(afile->vnode, &tvattr, &afs_osi_cred, current_proc());
220 #endif
221     AFS_GLOCK();
222     if (code == 0) {
223         astat->size = tvattr.va_size;
224         astat->mtime = tvattr.va_mtime.tv_sec;
225         astat->atime = tvattr.va_atime.tv_sec;
226     }
227     ReleaseWriteLock(&afs_xosi);
228     return code;
229 }
230
231 int
232 osi_UFSClose(struct osi_file *afile)
233 {
234     AFS_STATCNT(osi_Close);
235     if (afile->vnode) {
236 #ifdef AFS_DARWIN80_ENV
237         vnode_close(afile->vnode, O_RDWR, afs_osi_ctxtp);
238 #else
239         AFS_RELE(afile->vnode);
240 #endif
241     }
242
243     osi_FreeSmallSpace(afile);
244     return 0;
245 }
246
247 int
248 osi_UFSTruncate(struct osi_file *afile, afs_int32 asize)
249 {
250     afs_ucred_t *oldCred;
251     struct vattr tvattr;
252     afs_int32 code;
253     struct osi_stat tstat;
254     AFS_STATCNT(osi_Truncate);
255
256     /* This routine only shrinks files, and most systems
257      * have very slow truncates, even when the file is already
258      * small enough.  Check now and save some time.
259      */
260     code = afs_osi_Stat(afile, &tstat);
261     if (code || tstat.size <= asize)
262         return code;
263     ObtainWriteLock(&afs_xosi, 321);
264     AFS_GUNLOCK();
265 #ifdef AFS_DARWIN80_ENV
266     VATTR_INIT(&tvattr);
267     VATTR_SET(&tvattr, va_size, asize);
268     code = vnode_setattr(afile->vnode, &tvattr, afs_osi_ctxtp);
269 #else
270     VATTR_NULL(&tvattr);
271     tvattr.va_size = asize;
272     code = VOP_SETATTR(afile->vnode, &tvattr, &afs_osi_cred, current_proc());
273 #endif
274     AFS_GLOCK();
275     ReleaseWriteLock(&afs_xosi);
276     return code;
277 }
278
279 void
280 #ifdef AFS_DARWIN80_ENV
281 osi_DisableAtimes(vnode_t avp)
282 #else
283 osi_DisableAtimes(struct vnode *avp)
284 #endif
285 {
286 #ifdef AFS_DARWIN80_ENV
287     struct vnode_attr vap;
288
289     VATTR_INIT(&vap);
290     VATTR_CLEAR_SUPPORTED(&vap, va_access_time);
291     vnode_setattr(avp, &vap, afs_osi_ctxtp);
292 #else
293     if (afs_CacheFSType == AFS_APPL_UFS_CACHE) {
294         struct inode *ip = VTOI(avp);
295         ip->i_flag &= ~IN_ACCESS;
296     }
297 #ifdef VTOH                     /* can't do this without internals */
298     else if (afs_CacheFSType == AFS_APPL_HFS_CACHE) {
299         struct hfsnode *hp = VTOH(avp);
300         hp->h_nodeflags &= ~IN_ACCESS;
301     }
302 #endif
303 #endif
304 }
305
306
307 /* Generic read interface */
308 int
309 afs_osi_Read(struct osi_file *afile, int offset, void *aptr,
310              afs_int32 asize)
311 {
312     afs_ucred_t *oldCred;
313     afs_size_t resid;
314     afs_int32 code;
315 #ifdef AFS_DARWIN80_ENV
316     uio_t uio;
317 #endif
318     AFS_STATCNT(osi_Read);
319
320     /**
321       * If the osi_file passed in is NULL, panic only if AFS is not shutting
322       * down. No point in crashing when we are already shutting down
323       */
324     if (!afile) {
325         if (afs_shuttingdown == AFS_RUNNING)
326             osi_Panic("osi_Read called with null param");
327         else
328             return -EIO;
329     }
330
331     if (offset != -1)
332         afile->offset = offset;
333     AFS_GUNLOCK();
334 #ifdef AFS_DARWIN80_ENV
335     uio=uio_create(1, afile->offset, AFS_UIOSYS, UIO_READ);
336     uio_addiov(uio, CAST_USER_ADDR_T(aptr), asize);
337     code = VNOP_READ(afile->vnode, uio, IO_UNIT, afs_osi_ctxtp);
338     resid = AFS_UIO_RESID(uio);
339     uio_free(uio);
340 #else
341     code =
342         gop_rdwr(UIO_READ, afile->vnode, (caddr_t) aptr, asize, afile->offset,
343                  AFS_UIOSYS, IO_UNIT, &afs_osi_cred, &resid);
344 #endif
345     AFS_GLOCK();
346     if (code == 0) {
347         code = asize - resid;
348         afile->offset += code;
349         osi_DisableAtimes(afile->vnode);
350     } else {
351         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, resid,
352                    ICL_TYPE_INT32, code);
353         if (code > 0) {
354             code = -code;
355         }
356     }
357     return code;
358 }
359
360 /* Generic write interface */
361 int
362 afs_osi_Write(struct osi_file *afile, afs_int32 offset, void *aptr,
363               afs_int32 asize)
364 {
365     afs_ucred_t *oldCred;
366     afs_size_t resid;
367     afs_int32 code;
368 #ifdef AFS_DARWIN80_ENV
369     uio_t uio;
370 #endif
371     AFS_STATCNT(osi_Write);
372     if (!afile)
373         osi_Panic("afs_osi_Write called with null param");
374     if (offset != -1)
375         afile->offset = offset;
376     {
377         AFS_GUNLOCK();
378 #ifdef AFS_DARWIN80_ENV
379         uio=uio_create(1, afile->offset, AFS_UIOSYS, UIO_WRITE);
380         uio_addiov(uio, CAST_USER_ADDR_T(aptr), asize);
381         code = VNOP_WRITE(afile->vnode, uio, IO_UNIT, afs_osi_ctxtp);
382         resid = AFS_UIO_RESID(uio);
383         uio_free(uio);
384 #else
385         code =
386             gop_rdwr(UIO_WRITE, afile->vnode, (caddr_t) aptr, asize,
387                      afile->offset, AFS_UIOSYS, IO_UNIT, &afs_osi_cred,
388                      &resid);
389 #endif
390         AFS_GLOCK();
391     }
392     if (code == 0) {
393         code = asize - resid;
394         afile->offset += code;
395     } else {
396         if (code > 0) {
397             code = -code;
398         }
399     }
400     if (afile->proc) {
401         (*afile->proc) (afile, code);
402     }
403     return code;
404 }
405
406
407
408
409
410 void
411 shutdown_osifile(void)
412 {
413     AFS_STATCNT(shutdown_osifile);
414     if (afs_cold_shutdown) {
415         afs_osicred_initialized = 0;
416     }
417 }