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