97b699310835c39928a089429ce5b45747ef6eb4
[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
19 #if !defined(AFS_HPUX_ENV) && !defined(AFS_SGI_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN80_ENV)
20
21 #include "afs/sysincludes.h"    /* Standard vendor system headers */
22 #include "afsincludes.h"        /* Afs-based standard headers */
23 #include "afs/afs_stats.h"      /* statistics */
24 #include "afs/afs_cbqueue.h"
25 #include "afs/nfsclient.h"
26 #include "afs/afs_osidnlc.h"
27
28
29
30 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
31 int afs_ustrategy(struct buf *abp, afs_ucred_t *credp)
32 #else
33 int afs_ustrategy(struct buf *abp)
34 #endif
35 {
36     afs_int32 code;
37     struct uio tuio;
38     struct iovec tiovec[1];
39     struct vcache *tvc = VTOAFS(abp->b_vp);
40     afs_int32 len = abp->b_bcount;
41 #ifdef  AFS_AIX41_ENV
42     struct ucred *credp;
43 #elif defined(UKERNEL)
44     afs_ucred_t *credp = get_user_struct()->u_cred;
45 #elif !defined(AFS_SUN5_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
46     afs_ucred_t *credp = u.u_cred;
47 #endif
48
49     memset(&tuio, 0, sizeof(tuio));
50     memset(&tiovec, 0, sizeof(tiovec));
51
52     AFS_STATCNT(afs_ustrategy);
53 #ifdef  AFS_AIX41_ENV
54     /*
55      * So that it won't change while reading it
56      */
57     ObtainReadLock(&tvc->lock);
58     if (tvc->credp) {
59         credp = tvc->credp;
60         crhold(credp);
61     } else {
62         credp = crref();
63     }
64     ReleaseReadLock(&tvc->lock);
65     osi_Assert(credp);
66 #endif
67 #ifdef AFS_FBSD_ENV
68     if (abp->b_iocmd == BIO_READ) {
69 #else
70     if ((abp->b_flags & B_READ) == B_READ) {
71 #endif
72         /* read b_bcount bytes into kernel address b_un.b_addr starting
73          * at byte DEV_BSIZE * b_blkno.  Bzero anything we can't read,
74          * and finally call iodone(abp).  File is in abp->b_vp.  Credentials
75          * are from u area??
76          */
77         tuio.afsio_iov = tiovec;
78         tuio.afsio_iovcnt = 1;
79 #if defined(AFS_SUN5_ENV) || defined(AFS_XBSD_ENV)
80 # ifdef AFS_64BIT_CLIENT
81 #  ifdef AFS_SUN5_ENV
82         tuio.afsio_offset = (afs_offs_t) ldbtob(abp->b_lblkno);
83 #  else
84         tuio.afsio_offset = (afs_offs_t) dbtob(abp->b_blkno);
85 #  endif
86 # else /* AFS_64BIT_CLIENT */
87         tuio.afsio_offset = (u_int) dbtob(abp->b_blkno);
88 # endif /* AFS_64BIT_CLIENT */
89 #else
90         tuio.afsio_offset = DEV_BSIZE * abp->b_blkno;
91 #endif
92 #if defined(AFS_NBSD40_ENV)
93         UIO_SETUP_SYSSPACE(&tuio);
94 #else
95         tuio.afsio_seg = AFS_UIOSYS;
96 #endif
97 #ifdef AFS_UIOFMODE
98         tuio.afsio_fmode = 0;
99 #endif
100         tuio.afsio_resid = abp->b_bcount;
101 #if defined(AFS_NBSD40_ENV) || defined(FBSD_STRUCT_BUF_NO_SAVEADDR)
102         tiovec[0].iov_base = abp->b_data;
103 #elif defined(AFS_XBSD_ENV)
104         tiovec[0].iov_base = abp->b_saveaddr;
105 #else
106         tiovec[0].iov_base = abp->b_un.b_addr;
107 #endif /* AFS_XBSD_ENV */
108         tiovec[0].iov_len = abp->b_bcount;
109         /* are user's credentials valid here?  probably, but this
110          * sure seems like the wrong things to do. */
111 #if     defined(AFS_SUN5_ENV)
112         code = afs_nlrdwr(VTOAFS(abp->b_vp), &tuio, UIO_READ, 0, credp);
113 #else
114         code = afs_rdwr(VTOAFS(abp->b_vp), &tuio, UIO_READ, 0, credp);
115 #endif
116         if (code == 0) {
117             if (tuio.afsio_resid > 0)
118 #if defined(AFS_NBSD40_ENV) || defined(FBSD_STRUCT_BUF_NO_SAVEADDR)
119                 memset((char *)abp->b_data + (uintptr_t)abp->b_bcount - tuio.afsio_resid, 0,
120                        tuio.afsio_resid);
121 #elif defined(AFS_XBSD_ENV)
122                 memset(abp->b_saveaddr + abp->b_bcount - tuio.afsio_resid, 0,
123                        tuio.afsio_resid);
124 #else
125                 memset(abp->b_un.b_addr + abp->b_bcount - tuio.afsio_resid, 0,
126                        tuio.afsio_resid);
127 #endif /* AFS_XBSD_ENV */
128 #ifdef  AFS_AIX32_ENV
129             /*
130              * If we read a block that is past EOF and the user was not storing
131              * to it, go ahead and write protect the page. This way we will detect
132              * storing beyond EOF in the future
133              */
134             if (dbtob(abp->b_blkno) + abp->b_bcount > tvc->f.m.Length) {
135                 if ((abp->b_flags & B_PFSTORE) == 0) {
136                     AFS_GUNLOCK();
137                     vm_protectp(tvc->segid, dbtob(abp->b_blkno) / PAGESIZE,
138                                 abp->b_bcount / PAGESIZE, RDONLY);
139                     AFS_GLOCK();
140                 }
141             }
142 #endif
143         }
144     } else {
145         tuio.afsio_iov = tiovec;
146         tuio.afsio_iovcnt = 1;
147 #if defined(AFS_SUN5_ENV)
148 #ifdef AFS_64BIT_CLIENT
149 #ifdef AFS_SUN5_ENV
150         tuio.afsio_offset = (afs_offs_t) ldbtob(abp->b_lblkno);
151 #else
152         tuio.afsio_offset = (afs_offs_t) dbtob(abp->b_blkno);
153 #endif
154 #else /* AFS_64BIT_CLIENT */
155         tuio.afsio_offset = (u_int) dbtob(abp->b_blkno);
156 #endif /* AFS_64BIT_CLIENT */
157 #ifdef  AFS_SUN5_ENV
158 #ifdef  AFS_SUN59_ENV
159         tuio.uio_limit = curproc->p_fsz_ctl.rlim_cur;
160 #else
161         tuio.uio_limit = u.u_rlimit[RLIMIT_FSIZE].rlim_cur;
162 #endif
163 #endif
164 #else
165         tuio.afsio_offset = DEV_BSIZE * abp->b_blkno;
166 #endif
167 #if defined(AFS_NBSD40_ENV)
168         UIO_SETUP_SYSSPACE(&tuio);
169 #else
170         tuio.afsio_seg = AFS_UIOSYS;
171 #endif
172 #ifdef AFS_UIOFMODE
173         tuio.afsio_fmode = 0;
174 #endif
175 #ifdef  AFS_AIX32_ENV
176         /*
177          * XXX It this really right? Ideally we should always write block size multiple
178          * and not any arbitrary size, right? XXX
179          */
180         len = MIN(len, tvc->f.m.Length - dbtob(abp->b_blkno));
181 #endif
182         tuio.afsio_resid = len;
183 #if defined(AFS_NBSD40_ENV) || defined(FBSD_STRUCT_BUF_NO_SAVEADDR)
184         tiovec[0].iov_base = abp->b_data;
185 #elif defined(AFS_XBSD_ENV)
186         tiovec[0].iov_base = abp->b_saveaddr;
187 #else
188         tiovec[0].iov_base = abp->b_un.b_addr;
189 #endif /* AFS_XBSD_ENV */
190         tiovec[0].iov_len = len;
191         /* are user's credentials valid here?  probably, but this
192          * sure seems like the wrong things to do. */
193 #if     defined(AFS_SUN5_ENV)
194         code = afs_nlrdwr(VTOAFS(abp->b_vp), &tuio, UIO_WRITE, 0, credp);
195 #else
196         code = afs_rdwr(VTOAFS(abp->b_vp), &tuio, UIO_WRITE, 0, credp);
197 #endif
198     }
199
200 #if defined (AFS_XBSD_ENV)
201     if (code) {
202         abp->b_error = code;
203 #if !defined(AFS_FBSD_ENV) && !defined(AFS_NBSD50_ENV)
204         abp->b_flags |= B_ERROR;
205 #endif
206     }
207 #endif
208
209 #if defined(AFS_AIX32_ENV)
210     crfree(credp);
211 #elif defined(AFS_FBSD60_ENV)
212     (*abp->b_iodone)(abp);
213 #elif defined(AFS_FBSD_ENV)
214     biodone(&abp->b_io);
215 #elif defined(AFS_NBSD40_ENV)
216     abp->b_resid = tuio.uio_resid;
217     biodone(abp);
218 #elif defined(AFS_XBSD_ENV)
219     biodone(abp);
220 #elif !defined(AFS_SUN5_ENV)
221     iodone(abp);
222 #endif
223
224     afs_Trace3(afs_iclSetp, CM_TRACE_STRATEGYDONE, ICL_TYPE_POINTER, tvc,
225                ICL_TYPE_INT32, code, ICL_TYPE_LONG, tuio.afsio_resid);
226     return code;
227 }
228
229 #endif /* !AFS_HPUX_ENV  && !AFS_SGI_ENV && !AFS_LINUX20_ENV */