afs: Indicate error from afs_osi_Read/Write better
[openafs.git] / src / afs / NBSD / 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 #include "afs/sysincludes.h"    /* Standard vendor system headers */
14 #include "afs/afsincludes.h"    /* Afs-based standard headers */
15 #include "afs/afs_stats.h"      /* afs statistics */
16
17
18 int afs_osicred_initialized;
19 afs_lock_t afs_xosi;            /* lock is for tvattr */
20 extern struct osi_dev cacheDev;
21 extern struct mount *afs_cacheVfsp;
22
23 void *
24 osi_UFSOpen(afs_dcache_id_t *ainode)
25 {
26     struct osi_file *afile;
27     struct vnode *vp;
28     extern int cacheDiskType;
29     afs_int32 code;
30
31     AFS_STATCNT(osi_UFSOpen);
32     if (cacheDiskType != AFS_FCACHE_TYPE_UFS)
33         osi_Panic("UFSOpen called for non-UFS cache\n");
34     afile = (struct osi_file *)osi_AllocSmallSpace(sizeof(struct osi_file));
35     AFS_GUNLOCK();
36     code = VFS_VGET(cacheDev.mp, (ino_t) ainode->ufs, &vp);
37     AFS_GLOCK();
38     if (code == 0 && vp->v_type == VNON)
39         code = ENOENT;
40     if (code) {
41         osi_FreeSmallSpace(afile);
42         osi_Panic("UFSOpen: igetinode failed");
43     }
44 #if defined(AFS_NBSD60_ENV)
45     VOP_UNLOCK(vp);
46 #else
47     VOP_UNLOCK(vp, 0);
48 #endif
49     afile->vnode = vp;
50     afile->size = VTOI(vp)->i_ffs1_size;
51     afile->offset = 0;
52     afile->proc = NULL;
53     return (void *)afile;
54 }
55
56 int
57 afs_osi_Stat(struct osi_file *afile, struct osi_stat *astat)
58 {
59     afs_int32 code;
60     struct vattr tvattr;
61
62     AFS_STATCNT(osi_Stat);
63     ObtainWriteLock(&afs_xosi, 320);
64     AFS_GUNLOCK();
65 #ifdef AFS_NBSD50_ENV
66         code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp);
67 #else
68     code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp,
69                        osi_curproc());
70 #endif
71     AFS_GLOCK();
72     if (code == 0) {
73         astat->size = afile->size = tvattr.va_size;
74         astat->mtime = tvattr.va_mtime.tv_sec;
75         astat->atime = tvattr.va_atime.tv_sec;
76     }
77     ReleaseWriteLock(&afs_xosi);
78     return code;
79 }
80
81 int
82 osi_UFSClose(struct osi_file *afile)
83 {
84     AFS_STATCNT(osi_Close);
85
86     if (afile->vnode)
87         AFS_RELE(afile->vnode);
88
89     osi_FreeSmallSpace(afile);
90     return 0;
91 }
92
93 int
94 osi_UFSTruncate(struct osi_file *afile, afs_int32 asize)
95 {
96     struct vattr tvattr;
97     afs_int32 code;
98     struct osi_stat tstat;
99
100     AFS_STATCNT(osi_Truncate);
101
102     /*
103      * This routine only shrinks files, and most systems
104      * have very slow truncates, even when the file is already
105      * small enough.  Check now and save some time.
106      */
107     code = afs_osi_Stat(afile, &tstat);
108     if (code || tstat.size <= asize)
109         return code;
110
111     ObtainWriteLock(&afs_xosi, 321);
112     VATTR_NULL(&tvattr);
113     tvattr.va_size = asize;
114     AFS_GUNLOCK();
115     VOP_LOCK(afile->vnode, LK_EXCLUSIVE | LK_RETRY);
116 #ifdef AFS_NBSD50_ENV
117     code = VOP_SETATTR(afile->vnode, &tvattr, afs_osi_credp);
118 #else
119     code = VOP_SETATTR(afile->vnode, &tvattr, afs_osi_credp,
120                        osi_curproc());
121 #endif
122 #ifdef AFS_NBSD60_ENV
123     VOP_UNLOCK(afile->vnode);
124 #else
125     VOP_UNLOCK(afile->vnode, 0);
126 #endif
127     AFS_GLOCK();
128     if (code == 0)
129         afile->size = asize;
130     ReleaseWriteLock(&afs_xosi);
131     return code;
132 }
133
134 void
135 osi_DisableAtimes(struct vnode *avp)
136 {
137 #if 0
138     VTOI(avp)->i_flag &= ~IN_ACCESS;
139 #endif
140 }
141
142
143 /* Generic read interface */
144 int
145 afs_osi_Read(struct osi_file *afile, int offset, void *aptr, afs_int32 asize)
146 {
147     size_t resid;
148     afs_int32 code;
149
150     AFS_STATCNT(osi_Read);
151
152     /*
153      * If the osi_file passed in is NULL, panic only if AFS is not shutting
154      * down. No point in crashing when we are already shutting down
155      */
156     if (!afile) {
157         if (!afs_shuttingdown)
158             osi_Panic("osi_Read called with null param");
159         else
160             return -EIO;
161     }
162
163     if (offset != -1)
164         afile->offset = offset;
165     AFS_GUNLOCK();
166     code =
167         vn_rdwr(UIO_READ, afile->vnode, aptr, asize, afile->offset,
168                 AFS_UIOSYS, IO_UNIT, afs_osi_credp, &resid,
169                 osi_curproc());
170     AFS_GLOCK();
171     if (code == 0) {
172         code = asize - resid;
173         afile->offset += code;
174         osi_DisableAtimes(afile->vnode);
175     } else {
176         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, resid,
177                    ICL_TYPE_INT32, code);
178         if (code > 0) {
179             code *= -1;
180         }
181     }
182     return code;
183 }
184
185 /* Generic write interface */
186 int
187 afs_osi_Write(struct osi_file *afile, afs_int32 offset, void *aptr,
188               afs_int32 asize)
189 {
190     size_t resid;
191     afs_int32 code;
192
193     AFS_STATCNT(osi_Write);
194     if (!afile)
195         osi_Panic("afs_osi_Write called with null afile");
196     if (offset != -1)
197         afile->offset = offset;
198
199     AFS_GUNLOCK();
200     code =
201         vn_rdwr(UIO_WRITE, afile->vnode, aptr, asize, afile->offset,
202                 AFS_UIOSYS, IO_UNIT, afs_osi_credp, &resid, osi_curproc());
203     AFS_GLOCK();
204
205     if (code == 0) {
206         code = asize - resid;
207         afile->offset += code;
208         if (afile->offset > afile->size)
209             afile->size = afile->offset;
210     } else {
211         if (code > 0) {
212             code *= -1;
213         }
214     }
215
216     if (afile->proc)
217         (*afile->proc) (afile, code);
218
219     return code;
220 }
221
222 /*
223  * This work should be handled by physstrat in ca/machdep.c.  This routine
224  * written from the RT NFS port strategy routine.  It has been generalized a
225  * bit, but should still be pretty clear.
226  */
227 int
228 afs_osi_MapStrategy(int (*aproc)(struct buf *), struct buf *bp)
229 {
230     afs_int32 returnCode;
231
232     AFS_STATCNT(osi_MapStrategy);
233     returnCode = (*aproc) (bp);
234
235     return returnCode;
236 }
237
238 void
239 shutdown_osifile(void)
240 {
241     AFS_STATCNT(shutdown_osifile);
242     if (afs_cold_shutdown)
243         afs_osicred_initialized = 0;
244 }