afs: Indicate error from afs_osi_Read/Write better
[openafs.git] / src / afs / HPUX / 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"      /* igetinode() */
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 vfs *afs_cacheVfsp;
25
26
27 void *
28 osi_UFSOpen(afs_dcache_id_t *ainode)
29 {
30     struct inode *ip;
31     struct osi_file *afile = NULL;
32     extern int cacheDiskType;
33     afs_int32 code = 0;
34     int dummy;
35     AFS_STATCNT(osi_UFSOpen);
36     if (cacheDiskType != AFS_FCACHE_TYPE_UFS) {
37         osi_Panic("UFSOpen called for non-UFS cache\n");
38     }
39     if (!afs_osicred_initialized) {
40         /* valid for alpha_osf, SunOS, Ultrix */
41         memset(&afs_osi_cred, 0, sizeof(afs_ucred_t));
42         crhold(&afs_osi_cred);  /* don't let it evaporate, since it is static */
43         afs_osicred_initialized = 1;
44     }
45     afile = (struct osi_file *)osi_AllocSmallSpace(sizeof(struct osi_file));
46     setuerror(0);
47     AFS_GUNLOCK();
48     ip = (struct inode *)igetinode(afs_cacheVfsp, (dev_t) cacheDev.dev,
49                                    (ino_t) ainode->ufs, &dummy);
50     AFS_GLOCK();
51     if (getuerror()) {
52         osi_FreeSmallSpace(afile);
53         osi_Panic("UFSOpen: igetinode failed");
54     }
55     iunlock(ip);
56     afile->vnode = ITOV(ip);
57     afile->size = VTOI(afile->vnode)->i_size;
58     afile->offset = 0;
59     afile->proc = (int (*)())0;
60     return (void *)afile;
61 }
62
63 int
64 afs_osi_Stat(struct osi_file *afile, struct osi_stat *astat)
65 {
66     afs_int32 code;
67     struct vattr tvattr;
68     AFS_STATCNT(osi_Stat);
69     ObtainWriteLock(&afs_xosi, 320);
70     AFS_GUNLOCK();
71     code = VOP_GETATTR(afile->vnode, &tvattr, &afs_osi_cred, VSYNC);
72     AFS_GLOCK();
73     if (code == 0) {
74         astat->size = tvattr.va_size;
75         astat->mtime = tvattr.va_mtime.tv_sec;
76         astat->atime = tvattr.va_atime.tv_sec;
77     }
78     ReleaseWriteLock(&afs_xosi);
79     return code;
80 }
81
82 int
83 osi_UFSClose(struct osi_file *afile)
84 {
85     AFS_STATCNT(osi_Close);
86     if (afile->vnode) {
87         AFS_RELE(afile->vnode);
88     }
89
90     osi_FreeSmallSpace(afile);
91     return 0;
92 }
93
94 int
95 osi_UFSTruncate(struct osi_file *afile, afs_int32 asize)
96 {
97     afs_ucred_t *oldCred;
98     struct vattr tvattr;
99     afs_int32 code;
100     struct osi_stat tstat;
101     AFS_STATCNT(osi_Truncate);
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     ObtainWriteLock(&afs_xosi, 321);
111     VATTR_NULL(&tvattr);
112     /* note that this credential swapping stuff is only necessary because
113      * of ufs's references directly to u.u_cred instead of to
114      * credentials parameter.  Probably should fix ufs some day. */
115     oldCred = p_cred(u.u_procp);
116     set_p_cred(u.u_procp, &afs_osi_cred);
117     tvattr.va_size = asize;
118     AFS_GUNLOCK();
119     code = VOP_SETATTR(afile->vnode, &tvattr, &afs_osi_cred, 0);
120     AFS_GLOCK();
121     set_p_cred(u.u_procp, oldCred);     /* restore */
122     ReleaseWriteLock(&afs_xosi);
123     return code;
124 }
125
126 void
127 osi_DisableAtimes(struct vnode *avp)
128 {
129     struct inode *ip = VTOI(avp);
130     ip->i_flag &= ~IACC;
131 }
132
133
134 /* Generic read interface */
135 int
136 afs_osi_Read(struct osi_file *afile, int offset, void *aptr,
137              afs_int32 asize)
138 {
139     afs_ucred_t *oldCred;
140     long resid;
141     afs_int32 code;
142     afs_int32 cnt1 = 0;
143     AFS_STATCNT(osi_Read);
144
145     /**
146       * If the osi_file passed in is NULL, panic only if AFS is not shutting
147       * down. No point in crashing when we are already shutting down
148       */
149     if (!afile) {
150         if (!afs_shuttingdown)
151             osi_Panic("osi_Read called with null param");
152         else
153             return -EIO;
154     }
155
156     if (offset != -1)
157         afile->offset = offset;
158   retry_IO:
159     AFS_GUNLOCK();
160     code =
161         gop_rdwr(UIO_READ, afile->vnode, (caddr_t) aptr, asize, afile->offset,
162                  AFS_UIOSYS, IO_UNIT, &resid);
163     AFS_GLOCK();
164     if (code == 0) {
165         code = asize - resid;
166         afile->offset += code;
167         osi_DisableAtimes(afile->vnode);
168     } else {
169         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32,
170                    (afs_int32) resid, ICL_TYPE_INT32, code);
171         /*
172          * To handle periodic low-level EFAULT failures that we've seen with the
173          * Weitek chip; in all observed failed cases a second read succeeded.
174          */
175         if ((code == EFAULT) && (cnt1++ < 5)) {
176             afs_stats_cmperf.osiread_efaults++;
177             goto retry_IO;
178         }
179         setuerror(code);
180         if (code > 0) {
181             code *= -1;
182         }
183     }
184     return code;
185 }
186
187 /* Generic write interface */
188 int
189 afs_osi_Write(struct osi_file *afile, afs_int32 offset, void *aptr,
190               afs_int32 asize)
191 {
192     afs_ucred_t *oldCred;
193     long resid;
194     afs_int32 code;
195     AFS_STATCNT(osi_Write);
196     if (!afile)
197         osi_Panic("afs_osi_Write called with null param");
198     if (offset != -1)
199         afile->offset = offset;
200     AFS_GUNLOCK();
201     code =
202         gop_rdwr(UIO_WRITE, afile->vnode, (caddr_t) aptr, asize,
203                  afile->offset, AFS_UIOSYS, IO_UNIT, &resid);
204     AFS_GLOCK();
205     if (code == 0) {
206         code = asize - resid;
207         afile->offset += code;
208     } else {
209         if (code == ENOSPC)
210             afs_warnuser
211                 ("\n\n\n*** Cache partition is FULL - Decrease cachesize!!! ***\n\n");
212         setuerror(code);
213         if (code > 0) {
214             code *= -1;
215         }
216     }
217     if (afile->proc) {
218         (*afile->proc) (afile, code);
219     }
220     return code;
221 }
222
223
224 void
225 shutdown_osifile(void)
226 {
227     AFS_STATCNT(shutdown_osifile);
228     if (afs_cold_shutdown) {
229         afs_osicred_initialized = 0;
230     }
231 }