450312ec10c2f46f45ff13f5876194459ccc77a0
[openafs.git] / src / afs / DUX / 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
20
21 int afs_osicred_initialized = 0;
22 struct AFS_UCRED afs_osi_cred;
23 afs_lock_t afs_xosi;            /* lock is for tvattr */
24 extern struct osi_dev cacheDev;
25 extern struct mount *afs_cacheVfsp;
26
27
28 void *
29 osi_UFSOpen(afs_int32 ainode)
30 {
31     static struct vnode *tags_vnode = NULL;
32     struct inode *ip;
33     register struct osi_file *afile = NULL;
34     extern int cacheDiskType;
35     afs_int32 code = 0;
36     int dummy;
37     AFS_STATCNT(osi_UFSOpen);
38     if (cacheDiskType != AFS_FCACHE_TYPE_UFS)
39         osi_Panic("UFSOpen called for non-UFS cache\n");
40
41     afile = (struct osi_file *)osi_AllocSmallSpace(sizeof(struct osi_file));
42     AFS_GUNLOCK();
43
44     switch (afs_cacheVfsp->m_stat.f_type) {
45     case MOUNT_UFS:
46         code =
47             igetinode(afs_cacheVfsp, (dev_t) cacheDev.dev, (ino_t) ainode,
48                       &ip, &dummy);
49         if (code) {
50             osi_FreeSmallSpace(afile);
51             osi_Panic("UFSOpen: igetinode failed");
52         }
53         IN_UNLOCK(ip);
54         afile->vnode = ITOV(ip);
55         afile->size = VTOI(afile->vnode)->i_size;
56         afile->offset = 0;
57         afile->proc = NULL;
58         afile->inum = ainode;   /* for hint validity checking */
59         break;
60     case MOUNT_MSFS:{
61             char path[1024];
62             struct nameidata nd, *ndp = &nd;
63             struct utask_nd utnd = { NULL, NULL };
64             struct vattr attr;
65
66             memset(&nd, 0, sizeof(nd));
67             ndp->ni_utnd = &utnd;
68             ndp->ni_nameiop = LOOKUP;
69             ndp->ni_cred = &afs_osi_cred;
70             ndp->ni_segflg = UIO_SYSSPACE;
71
72             /* get hold of a vnode for the .tags directory, so we can
73              * lookup files relative to it */
74             if (tags_vnode == NULL) {
75                 ndp->ni_cdir = afs_cacheVfsp->m_vnodecovered;
76                 strcpy(path, afs_cacheVfsp->m_stat.f_mntonname);
77                 strcat(path, "/.tags");
78                 ndp->ni_dirp = path;
79                 if ((code = namei(ndp)))
80                     osi_Panic("failed to lookup %s (%d)", path, code);
81                 tags_vnode = ndp->ni_vp;
82             }
83             sprintf(path, "%d", ainode);
84             ndp->ni_dirp = path;
85             ndp->ni_cdir = tags_vnode;
86             if ((code = namei(ndp)))
87                 osi_Panic("failed to lookup %s (%d)", path, code);
88
89             /* XXX this sucks, chances are we're going to do this again right
90              * away, but apparently we can't just set the size to 0 */
91             VOP_GETATTR(ndp->ni_vp, &attr, &afs_osi_cred, code);
92             if (code)
93                 osi_Panic("failed to stat %s (%d)", path, code);
94
95             afile->vnode = ndp->ni_vp;
96             afile->size = attr.va_size;
97             afile->offset = 0;
98             afile->proc = NULL;
99             afile->inum = ainode;       /* for hint validity checking */
100             break;
101         }
102     default:
103         osi_Panic("UFSOpen called for unknown cache-type (%d)",
104                   afs_cacheVfsp->m_stat.f_type);
105     }
106
107     AFS_GLOCK();
108     return afile;
109 }
110
111 int
112 afs_osi_Stat(register struct osi_file *afile, register struct osi_stat *astat)
113 {
114     register afs_int32 code;
115     struct vattr tvattr;
116     AFS_STATCNT(osi_Stat);
117     MObtainWriteLock(&afs_xosi, 320);
118     AFS_GUNLOCK();
119     VOP_GETATTR(afile->vnode, &tvattr, &afs_osi_cred, code);
120     AFS_GLOCK();
121     if (code == 0) {
122         astat->size = tvattr.va_size;
123         astat->blksize = tvattr.va_blocksize;
124         astat->mtime = tvattr.va_mtime.tv_sec;
125         astat->atime = tvattr.va_atime.tv_sec;
126     }
127     MReleaseWriteLock(&afs_xosi);
128     return code;
129 }
130
131 int
132 osi_UFSClose(register struct osi_file *afile)
133 {
134     AFS_STATCNT(osi_Close);
135     if (afile->vnode) {
136         AFS_RELE(afile->vnode);
137     }
138
139     osi_FreeSmallSpace(afile);
140     return 0;
141 }
142
143 int
144 osi_UFSTruncate(register struct osi_file *afile, afs_int32 asize)
145 {
146     struct AFS_UCRED *oldCred;
147     struct vattr tvattr;
148     register afs_int32 code;
149     struct osi_stat tstat;
150     AFS_STATCNT(osi_Truncate);
151
152     /* This routine only shrinks files, and most systems
153      * have very slow truncates, even when the file is already
154      * small enough.  Check now and save some time.
155      */
156     code = afs_osi_Stat(afile, &tstat);
157     if (code || tstat.size <= asize)
158         return code;
159     MObtainWriteLock(&afs_xosi, 321);
160     VATTR_NULL(&tvattr);
161     /* note that this credential swapping stuff is only necessary because
162      * of ufs's references directly to u.u_cred instead of to
163      * credentials parameter.  Probably should fix ufs some day. */
164     oldCred = u.u_cred;         /* remember old credentials pointer  */
165     u.u_cred = &afs_osi_cred;   /* temporarily use superuser credentials */
166     tvattr.va_size = asize;
167     AFS_GUNLOCK();
168     VOP_SETATTR(afile->vnode, &tvattr, &afs_osi_cred, code);
169     AFS_GLOCK();
170     u.u_cred = oldCred;         /* restore */
171     MReleaseWriteLock(&afs_xosi);
172     return code;
173 }
174
175 void
176 osi_DisableAtimes(struct vnode *avp)
177 {
178     struct inode *ip;
179     assert(avp->v_tag == VT_UFS);
180     ip = VTOI(avp);
181     ip->i_flag &= ~IACC;
182 }
183
184
185 /* Generic read interface */
186 int
187 afs_osi_Read(register struct osi_file *afile, int offset, void *aptr,
188              afs_int32 asize)
189 {
190     struct AFS_UCRED *oldCred;
191     unsigned int resid;
192     register afs_int32 code;
193     register afs_int32 cnt1 = 0;
194     AFS_STATCNT(osi_Read);
195
196     /**
197       * If the osi_file passed in is NULL, panic only if AFS is not shutting
198       * down. No point in crashing when we are already shutting down
199       */
200     if (!afile) {
201         if (!afs_shuttingdown)
202             osi_Panic("osi_Read called with null param");
203         else
204             return EIO;
205     }
206
207     if (offset != -1)
208         afile->offset = offset;
209     AFS_GUNLOCK();
210     code =
211         gop_rdwr(UIO_READ, afile->vnode, (caddr_t) aptr, asize, afile->offset,
212                  AFS_UIOSYS, IO_UNIT, &afs_osi_cred, &resid);
213     AFS_GLOCK();
214     if (code == 0) {
215         code = asize - resid;
216         afile->offset += code;
217         osi_DisableAtimes(afile->vnode);
218     } else {
219         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, resid,
220                    ICL_TYPE_INT32, code);
221         code = -1;
222     }
223     return code;
224 }
225
226 /* Generic write interface */
227 int
228 afs_osi_Write(register struct osi_file *afile, afs_int32 offset, void *aptr,
229               afs_int32 asize)
230 {
231     struct AFS_UCRED *oldCred;
232     unsigned int resid;
233     register afs_int32 code;
234     AFS_STATCNT(osi_Write);
235     if (!afile)
236         osi_Panic("afs_osi_Write called with null param");
237     if (offset != -1)
238         afile->offset = offset;
239     {
240         struct ucred *tmpcred = u.u_cred;
241         u.u_cred = &afs_osi_cred;
242         AFS_GUNLOCK();
243         code =
244             gop_rdwr(UIO_WRITE, afile->vnode, (caddr_t) aptr, asize,
245                      afile->offset, AFS_UIOSYS, IO_UNIT, &afs_osi_cred,
246                      &resid);
247         AFS_GLOCK();
248         u.u_cred = tmpcred;
249     }
250     if (code == 0) {
251         code = asize - resid;
252         afile->offset += code;
253     } else {
254         code = -1;
255     }
256     if (afile->proc) {
257         (*afile->proc) (afile, code);
258     }
259     return code;
260 }
261
262
263 /*  This work should be handled by physstrat in ca/machdep.c.
264     This routine written from the RT NFS port strategy routine.
265     It has been generalized a bit, but should still be pretty clear. */
266 int
267 afs_osi_MapStrategy(int (*aproc) (), register struct buf *bp)
268 {
269     afs_int32 returnCode;
270
271     AFS_STATCNT(osi_MapStrategy);
272     returnCode = (*aproc) (bp);
273
274     return returnCode;
275 }
276
277
278
279 void
280 shutdown_osifile(void)
281 {
282     extern int afs_cold_shutdown;
283
284     AFS_STATCNT(shutdown_osifile);
285     if (afs_cold_shutdown) {
286         afs_osicred_initialized = 0;
287     }
288 }