53ab95983b58b0466802957e99372fcdb862f925
[openafs.git] / src / afs / VNOPS / afs_vnop_strategy.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 /*
11  * Implements:
12  * afs_ustrategy
13  */
14
15 #include <afsconfig.h>
16 #include "../afs/param.h"
17
18 RCSID("$Header$");
19
20 #if !defined(AFS_HPUX_ENV) && !defined(AFS_SGI_ENV) && !defined(AFS_LINUX20_ENV)
21
22 #include "../afs/sysincludes.h" /* Standard vendor system headers */
23 #include "../afs/afsincludes.h" /* Afs-based standard headers */
24 #include "../afs/afs_stats.h" /* statistics */
25 #include "../afs/afs_cbqueue.h"
26 #include "../afs/nfsclient.h"
27 #include "../afs/afs_osidnlc.h"
28
29
30
31
32 #if     defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
33 afs_ustrategy(abp, credp)
34     struct AFS_UCRED *credp;
35 #else
36 afs_ustrategy(abp)
37 #endif
38     register struct buf *abp; {
39     register afs_int32 code;
40     struct uio tuio;
41     register struct vcache *tvc = (struct vcache *) abp->b_vp;
42     register afs_int32 len = abp->b_bcount;
43 #if     !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
44 #ifdef  AFS_AIX41_ENV
45     struct ucred *credp;
46 #else
47     struct AFS_UCRED *credp = u.u_cred;
48 #endif
49 #endif
50 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
51     int async = abp->b_flags & B_ASYNC;
52 #endif
53     struct iovec tiovec[1];
54
55     AFS_STATCNT(afs_ustrategy);
56 #ifdef  AFS_AIX41_ENV
57     /*
58      * So that it won't change while reading it
59      */
60     ObtainReadLock(&tvc->lock);
61     if (tvc->credp) {   
62         credp = tvc->credp;
63         crhold(credp);
64     } else {
65         credp = crref();
66     }
67     ReleaseReadLock(&tvc->lock);
68     osi_Assert(credp);
69 #endif
70     if ((abp->b_flags & B_READ) == B_READ) {
71         /* read b_bcount bytes into kernel address b_un.b_addr starting
72             at byte DEV_BSIZE * b_blkno.  Bzero anything we can't read,
73             and finally call iodone(abp).  File is in abp->b_vp.  Credentials
74             are from u area??
75         */
76         tuio.afsio_iov = tiovec;
77         tuio.afsio_iovcnt = 1;
78 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_FBSD_ENV)
79         tuio.afsio_offset = (u_int) dbtob(abp->b_blkno);
80 #if     defined(AFS_SUN5_ENV)
81         tuio._uio_offset._p._u = 0;
82 #endif
83 #else
84         tuio.afsio_offset = DEV_BSIZE * abp->b_blkno;
85 #endif
86         tuio.afsio_seg = AFS_UIOSYS;
87 #ifdef AFS_UIOFMODE
88         tuio.afsio_fmode = 0;
89 #endif
90         tuio.afsio_resid = abp->b_bcount;
91 #if defined(AFS_FBSD_ENV)
92         tiovec[0].iov_base = abp->b_saveaddr;
93 #else
94         tiovec[0].iov_base = abp->b_un.b_addr;
95 #endif /* AFS_FBSD_ENV */
96         tiovec[0].iov_len = abp->b_bcount;
97         /* are user's credentials valid here?  probably, but this
98              sure seems like the wrong things to do. */
99 #if     defined(AFS_SUN5_ENV)
100         code = afs_nlrdwr((struct vcache *) abp->b_vp, &tuio, UIO_READ, 0, credp);
101 #else
102         code = afs_rdwr((struct vcache *) abp->b_vp, &tuio, UIO_READ, 0, credp);
103 #endif
104         if (code == 0) {
105             if (tuio.afsio_resid > 0)
106 #if defined(AFS_FBSD_ENV)
107                 memset(abp->b_saveaddr + abp->b_bcount - tuio.afsio_resid, 0, tuio.afsio_resid);
108 #else
109                 memset(abp->b_un.b_addr + abp->b_bcount - tuio.afsio_resid, 0, tuio.afsio_resid);
110 #endif /* AFS_FBSD_ENV */
111 #ifdef  AFS_AIX32_ENV
112             /*
113              * If we read a block that is past EOF and the user was not storing
114              * to it, go ahead and write protect the page. This way we will detect
115              * storing beyond EOF in the future
116              */
117             if (dbtob(abp->b_blkno) + abp->b_bcount > tvc->m.Length) {
118                 if ((abp->b_flags & B_PFSTORE) == 0) {
119                     AFS_GUNLOCK();
120                     vm_protectp(tvc->vmh, dbtob(abp->b_blkno)/PAGESIZE,
121                                 abp->b_bcount/PAGESIZE, RDONLY);
122                     AFS_GLOCK();
123                 }
124             }
125 #endif
126         }
127     }
128     else {
129         tuio.afsio_iov = tiovec;
130         tuio.afsio_iovcnt = 1;
131 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
132         tuio.afsio_offset = (u_int) dbtob(abp->b_blkno);
133 #ifdef  AFS_SUN5_ENV
134         tuio._uio_offset._p._u = 0;
135         tuio.uio_limit = u.u_rlimit[RLIMIT_FSIZE].rlim_cur;
136 #endif
137 #else
138         tuio.afsio_offset = DEV_BSIZE * abp->b_blkno;
139 #endif
140         tuio.afsio_seg = AFS_UIOSYS;
141 #ifdef AFS_UIOFMODE
142         tuio.afsio_fmode = 0;
143 #endif
144 #ifdef  AFS_AIX32_ENV   
145         /*
146          * XXX It this really right? Ideally we should always write block size multiple
147          * and not any arbitrary size, right? XXX
148          */
149         len = MIN(len, tvc->m.Length - dbtob(abp->b_blkno));
150 #endif
151 #ifdef  AFS_ALPHA_ENV
152         len = MIN(abp->b_bcount, ((struct vcache *)abp->b_vp)->m.Length - dbtob(abp->b_blkno));
153 #endif  /* AFS_ALPHA_ENV */
154         tuio.afsio_resid = len;
155 #if defined(AFS_FBSD_ENV)
156         tiovec[0].iov_base = abp->b_saveaddr;
157 #else
158         tiovec[0].iov_base = abp->b_un.b_addr;
159 #endif /* AFS_FBSD_ENV */
160         tiovec[0].iov_len = len;
161         /* are user's credentials valid here?  probably, but this
162              sure seems like the wrong things to do. */
163 #if     defined(AFS_SUN5_ENV)
164         code = afs_nlrdwr((struct vcache *) abp->b_vp, &tuio, UIO_WRITE, 0, credp);
165 #else
166         code = afs_rdwr((struct vcache *) abp->b_vp, &tuio, UIO_WRITE, 0, credp);
167 #endif
168     }
169 #if     !defined(AFS_AIX32_ENV) && !defined(AFS_SUN5_ENV)
170 #ifdef AFS_DUX40_ENV
171     if (code) {
172         abp->b_error = code;
173         abp->b_flags |= B_ERROR;
174     }
175     biodone(abp);
176     if (code && !(abp->b_flags & B_READ)) {
177         /* prevent ubc from retrying writes */
178         AFS_GUNLOCK();
179         ubc_invalidate(((struct vnode *)tvc)->v_object,
180                        (vm_offset_t)dbtob(abp->b_blkno),
181                        PAGE_SIZE, B_INVAL);
182         AFS_GLOCK();
183     }
184 #else  /* AFS_DUX40_ENV */
185     iodone(abp);
186 #endif /* AFS_DUX40_ENV */
187 #endif
188 #ifdef  AFS_AIX32_ENV
189     crfree(credp);
190 #endif
191     afs_Trace3(afs_iclSetp, CM_TRACE_STRATEGYDONE, ICL_TYPE_POINTER, tvc,
192                ICL_TYPE_INT32, code,
193                ICL_TYPE_LONG, tuio.afsio_resid);
194     return code;
195 }
196
197 #endif /* !AFS_HPUX_ENV  && !AFS_SGI_ENV && !AFS_LINUX20_ENV */